segfaults.nim 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2017 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This modules registers a signal handler that turns access violations /
  10. ## segfaults into a ``NilAccessError`` exception. To be able to catch
  11. ## a NilAccessError all you have to do is to import this module.
  12. ##
  13. ## Tested on these OSes: Linux, Windows, OSX
  14. # do allocate memory upfront:
  15. var se: ref NilAccessError
  16. new(se)
  17. se.name = "NilAccessError"
  18. se.msg = ""
  19. when defined(windows):
  20. include "../system/ansi_c"
  21. import winlean
  22. const
  23. EXCEPTION_ACCESS_VIOLATION = DWORD(0xc0000005)
  24. EXCEPTION_CONTINUE_SEARCH = Long(0)
  25. type
  26. PEXCEPTION_RECORD = ptr object
  27. exceptionCode: DWORD # other fields left out
  28. PEXCEPTION_POINTERS = ptr object
  29. exceptionRecord: PEXCEPTION_RECORD
  30. contextRecord: pointer
  31. VectoredHandler = proc (p: PEXCEPTION_POINTERS): LONG {.stdcall.}
  32. proc addVectoredExceptionHandler(firstHandler: ULONG,
  33. handler: VectoredHandler): pointer {.
  34. importc: "AddVectoredExceptionHandler", stdcall, dynlib: "kernel32.dll"}
  35. {.push stackTrace: off.}
  36. proc segfaultHandler(p: PEXCEPTION_POINTERS): LONG {.stdcall.} =
  37. if p.exceptionRecord.exceptionCode == EXCEPTION_ACCESS_VIOLATION:
  38. {.gcsafe.}:
  39. raise se
  40. else:
  41. result = EXCEPTION_CONTINUE_SEARCH
  42. {.pop.}
  43. discard addVectoredExceptionHandler(0, segfaultHandler)
  44. when false:
  45. {.push stackTrace: off.}
  46. proc segfaultHandler(sig: cint) {.noconv.} =
  47. {.gcsafe.}:
  48. rawRaise se
  49. {.pop.}
  50. c_signal(SIGSEGV, segfaultHandler)
  51. else:
  52. import posix
  53. var sa: Sigaction
  54. var SEGV_MAPERR {.importc, header: "<signal.h>".}: cint
  55. {.push stackTrace: off.}
  56. proc segfaultHandler(sig: cint, y: ptr SigInfo, z: pointer) {.noconv.} =
  57. if y.si_code == SEGV_MAPERR:
  58. {.gcsafe.}:
  59. raise se
  60. else:
  61. quit(1)
  62. {.pop.}
  63. discard sigemptyset(sa.sa_mask)
  64. sa.sa_sigaction = segfaultHandler
  65. sa.sa_flags = SA_SIGINFO or SA_NODEFER
  66. discard sigaction(SIGSEGV, sa)