summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2017-01-20 17:08:11 +0100
committerAraq <rumpf_a@web.de>2017-01-20 17:08:11 +0100
commitcdebcf23d94939690ebdd08151984d926d9b566e (patch)
tree3e542060b3b9f1c250a32615382502ba5182f024 /lib
parent64a7d2fd08c7f146260696e6c633420a95a3d4af (diff)
downloadNim-cdebcf23d94939690ebdd08151984d926d9b566e.tar.gz
new segfaults.nim stdlib module works on Windows
Diffstat (limited to 'lib')
-rw-r--r--lib/pure/segfaults.nim42
-rw-r--r--lib/system/excpt.nim7
2 files changed, 44 insertions, 5 deletions
diff --git a/lib/pure/segfaults.nim b/lib/pure/segfaults.nim
index 3c3b59449..c53abb4aa 100644
--- a/lib/pure/segfaults.nim
+++ b/lib/pure/segfaults.nim
@@ -10,6 +10,8 @@
 ## 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
 
 type
   NilAccessError* = object of SystemError ## \
@@ -18,17 +20,49 @@ type
 # do allocate memory upfront:
 var se: ref NilAccessError
 new(se)
+se.name = "NilAccessError"
 se.msg = ""
 
 when defined(windows):
   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(sig: cint) {.noconv.} =
-    {.gcsafe.}:
-      raise se
+  proc segfaultHandler(p: PEXCEPTION_POINTERS): LONG {.stdcall.} =
+    if p.exceptionRecord.exceptionCode == EXCEPTION_ACCESS_VIOLATION:
+      {.gcsafe.}:
+        raise se
+    else:
+      result = EXCEPTION_CONTINUE_SEARCH
   {.pop.}
-  c_signal(SIGSEGV, segfaultHandler)
+
+  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
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index d00ab64b1..b16590c92 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -212,6 +212,12 @@ proc quitOrDebug() {.inline.} =
   else:
     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) =
   if localRaiseHook != nil:
     if not localRaiseHook(e): return
@@ -371,5 +377,4 @@ when not defined(noSignalHandler):
 proc setControlCHook(hook: proc () {.noconv.} not nil) =
   # ugly cast, but should work on all architectures:
   type SignalHandler = proc (sign: cint) {.noconv, benign.}
-  {.deprecated: [TSignalHandler: SignalHandler].}
   c_signal(SIGINT, cast[SignalHandler](hook))