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
|
#
#
# 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
{.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 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 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)
|