new segfaults.nim stdlib module works on Windows

This commit is contained in:
Araq 2017-01-20 17:08:11 +01:00
commit cdebcf23d9
3 changed files with 48 additions and 5 deletions

View file

@ -10,6 +10,8 @@
## This modules registers a signal handler that turns access violations / ## This modules registers a signal handler that turns access violations /
## segfaults into a ``NilAccessError`` exception. To be able to catch ## segfaults into a ``NilAccessError`` exception. To be able to catch
## a NilAccessError all you have to do is to import this module. ## a NilAccessError all you have to do is to import this module.
##
## Tested on these OSes: Linux, Windows, OSX
type type
NilAccessError* = object of SystemError ## \ NilAccessError* = object of SystemError ## \
@ -18,15 +20,47 @@ type
# do allocate memory upfront: # do allocate memory upfront:
var se: ref NilAccessError var se: ref NilAccessError
new(se) new(se)
se.name = "NilAccessError"
se.msg = "" se.msg = ""
when defined(windows): when defined(windows):
include "$lib/system/ansi_c" include "$lib/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.} {.push stackTrace: off.}
proc segfaultHandler(sig: cint) {.noconv.} = proc segfaultHandler(sig: cint) {.noconv.} =
{.gcsafe.}: {.gcsafe.}:
raise se rawRaise se
{.pop.} {.pop.}
c_signal(SIGSEGV, segfaultHandler) c_signal(SIGSEGV, segfaultHandler)

View file

@ -212,6 +212,12 @@ proc quitOrDebug() {.inline.} =
else: else:
endbStep() # call the debugger endbStep() # call the debugger
when false:
proc rawRaise*(e: ref Exception) =
## undocumented. Do not use.
pushCurrentException(e)
c_longjmp(excHandler.context, 1)
proc raiseExceptionAux(e: ref Exception) = proc raiseExceptionAux(e: ref Exception) =
if localRaiseHook != nil: if localRaiseHook != nil:
if not localRaiseHook(e): return if not localRaiseHook(e): return
@ -371,5 +377,4 @@ when not defined(noSignalHandler):
proc setControlCHook(hook: proc () {.noconv.} not nil) = proc setControlCHook(hook: proc () {.noconv.} not nil) =
# ugly cast, but should work on all architectures: # ugly cast, but should work on all architectures:
type SignalHandler = proc (sign: cint) {.noconv, benign.} type SignalHandler = proc (sign: cint) {.noconv, benign.}
{.deprecated: [TSignalHandler: SignalHandler].}
c_signal(SIGINT, cast[SignalHandler](hook)) c_signal(SIGINT, cast[SignalHandler](hook))

View file

@ -18,6 +18,10 @@ proc main =
try: try:
var x: ptr int var x: ptr int
echo x[] echo x[]
try:
raise newException(ValueError, "not a crash")
except ValueError:
discard
except NilAccessError: except NilAccessError:
echo "caught a crash!" echo "caught a crash!"