segfaults.nim 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  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 ``NilAccessDefect`` exception. To be able to catch
  11. ## a NilAccessDefect all you have to do is to import this module.
  12. ##
  13. ## Tested on these OSes: Linux, Windows, OSX
  14. # xxx possibly broken on arm64, see bug #17178
  15. {.used.}
  16. # do allocate memory upfront:
  17. var se: ref NilAccessDefect
  18. new(se)
  19. se.name = "NilAccessDefect"
  20. se.msg = "Could not access value because it is nil."
  21. when defined(windows):
  22. include "../system/ansi_c"
  23. import std/winlean
  24. const
  25. EXCEPTION_ACCESS_VIOLATION = DWORD(0xc0000005'i32)
  26. EXCEPTION_CONTINUE_SEARCH = LONG(0)
  27. type
  28. PEXCEPTION_RECORD = ptr object
  29. exceptionCode: DWORD # other fields left out
  30. PEXCEPTION_POINTERS = ptr object
  31. exceptionRecord: PEXCEPTION_RECORD
  32. contextRecord: pointer
  33. VectoredHandler = proc (p: PEXCEPTION_POINTERS): LONG {.stdcall.}
  34. proc addVectoredExceptionHandler(firstHandler: ULONG,
  35. handler: VectoredHandler): pointer {.
  36. importc: "AddVectoredExceptionHandler", stdcall, dynlib: "kernel32.dll".}
  37. {.push stackTrace: off.}
  38. proc segfaultHandler(p: PEXCEPTION_POINTERS): LONG {.stdcall.} =
  39. if p.exceptionRecord.exceptionCode == EXCEPTION_ACCESS_VIOLATION:
  40. {.gcsafe.}:
  41. raise se
  42. else:
  43. result = EXCEPTION_CONTINUE_SEARCH
  44. {.pop.}
  45. discard addVectoredExceptionHandler(0, segfaultHandler)
  46. when false:
  47. {.push stackTrace: off.}
  48. proc segfaultHandler(sig: cint) {.noconv.} =
  49. {.gcsafe.}:
  50. rawRaise se
  51. {.pop.}
  52. c_signal(SIGSEGV, segfaultHandler)
  53. else:
  54. import std/posix
  55. var sa: Sigaction
  56. var SEGV_MAPERR {.importc, header: "<signal.h>".}: cint
  57. {.push stackTrace: off.}
  58. proc segfaultHandler(sig: cint, y: ptr SigInfo, z: pointer) {.noconv.} =
  59. if y.si_code == SEGV_MAPERR:
  60. {.gcsafe.}:
  61. raise se
  62. else:
  63. quit(1)
  64. {.pop.}
  65. discard sigemptyset(sa.sa_mask)
  66. sa.sa_sigaction = segfaultHandler
  67. sa.sa_flags = SA_SIGINFO or SA_NODEFER
  68. discard sigaction(SIGSEGV, sa)