segfaults.nim 2.2 KB

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