1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 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)
|