mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-29 17:34:43 +00:00
85 lines
2.1 KiB
Nim
85 lines
2.1 KiB
Nim
#
|
|
#
|
|
# 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
|
|
|
|
# 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: "<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)
|