diff options
Diffstat (limited to 'lib/pure/segfaults.nim')
-rw-r--r-- | lib/pure/segfaults.nim | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/lib/pure/segfaults.nim b/lib/pure/segfaults.nim new file mode 100644 index 000000000..65b059e86 --- /dev/null +++ b/lib/pure/segfaults.nim @@ -0,0 +1,88 @@ +# +# +# 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 ``NilAccessDefect`` exception. To be able to catch +## a NilAccessDefect all you have to do is to import this module. +## +## Tested on these OSes: Linux, Windows, OSX + +# xxx possibly broken on arm64, see bug #17178 + +{.used.} + +# do allocate memory upfront: +var se: ref NilAccessDefect +new(se) +se.name = "NilAccessDefect" +se.msg = "Could not access value because it is nil." + +when defined(windows): + include "../system/ansi_c" + + import std/winlean + + const + EXCEPTION_ACCESS_VIOLATION = DWORD(0xc0000005'i32) + 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 std/posix + + var sa: Sigaction + + var SEGV_MAPERR {.importc, header: "<signal.h>".}: cint + + {.push stackTrace: off.} + proc segfaultHandler(sig: cint, y: ptr 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) |