# # # Nim's Runtime Library # (c) Copyright 2017 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # ## This modules registers a signal handler that turns access violations / ## segfaults into a ``NilAccessError`` exception. To be able to catch ## a NilAccessError all you have to do is to import this module. ## ## Tested on these OSes: Linux, Windows, OSX type NilAccessError* = object of SystemError ## \ ## Raised on dereferences of ``nil`` pointers. # do allocate memory upfront: var se: ref NilAccessError new(se) se.name = "NilAccessError" se.msg = "" when defined(windows): include "../system/ansi_c" import winlean const EXCEPTION_ACCESS_VIOLATION = DWORD(0xc0000005) EXCEPTION_CONTINUE_SEARCH = Long(0) type PEXCEPTION_RECORD = ptr object exceptionCode: DWORD # other fields left out PEXCEPTION_POINTERS = ptr object exceptionRecord: PEXCEPTION_RECORD contextRecord: pointer VectoredHandler = proc (p: PEXCEPTION_POINTERS): LONG {.stdcall.} proc addVectoredExceptionHandler(firstHandler: ULONG, handler: VectoredHandler): pointer {. importc: "AddVectoredExceptionHandler", stdcall, dynlib: "kernel32.dll"} {.push stackTrace: off.} proc segfaultHandler(p: PEXCEPTION_POINTERS): LONG {.stdcall.} = if p.exceptionRecord.exceptionCode == EXCEPTION_ACCESS_VIOLATION: {.gcsafe.}: raise se else: result = EXCEPTION_CONTINUE_SEARCH {.pop.} discard addVectoredExceptionHandler(0, segfaultHandler) when false: {.push stackTrace: off.} proc segfaultHandler(sig: cint) {.noconv.} = {.gcsafe.}: rawRaise se {.pop.} c_signal(SIGSEGV, segfaultHandler) else: import posix var sa: Sigaction var SEGV_MAPERR {.importc, header: "".}: cint {.push stackTrace: off.} proc segfaultHandler(sig: cint, y: var SigInfo, z: pointer) {.noconv.} = if y.si_code == SEGV_MAPERR: {.gcsafe.}: raise se else: quit(1) {.pop.} discard sigemptyset(sa.sa_mask) sa.sa_sigaction = segfaultHandler sa.sa_flags = SA_SIGINFO or SA_NODEFER discard sigaction(SIGSEGV, sa)