diff options
author | alaviss <leorize+oss@disroot.org> | 2021-02-19 08:29:21 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-19 00:29:21 -0800 |
commit | ccc0667c29256ec1303e1d4280f013b380d85828 (patch) | |
tree | 88fda1a9341491f8afdff001a034e1a537ee0ddd | |
parent | 95664e15247d678476d64a1c81f7c19b163e823c (diff) | |
download | Nim-ccc0667c29256ec1303e1d4280f013b380d85828.tar.gz |
system/excpt: let the OS handle termination on signal (#16712)
-rw-r--r-- | changelog.md | 8 | ||||
-rw-r--r-- | lib/system/ansi_c.nim | 9 | ||||
-rw-r--r-- | lib/system/excpt.nim | 12 | ||||
-rw-r--r-- | tests/system/tsigexitcode.nim | 20 |
4 files changed, 46 insertions, 3 deletions
diff --git a/changelog.md b/changelog.md index d016d2604..3f8ee3c3d 100644 --- a/changelog.md +++ b/changelog.md @@ -159,6 +159,14 @@ provided by the operating system. `ValueError` when the real command line is not available. `parseopt` was previously excluded from `prelude` for JS, as it could not be imported. +- On POSIX systems, the default signal handlers used for Nim programs (it's + used for printing the stacktrace on fatal signals) will now re-raise the + signal for the OS default handlers to handle. + + This lets the OS perform its default actions, which might include core + dumping (on select signals) and notifying the parent process about the cause + of termination. + ## Language changes - `nimscript` now handles `except Exception as e`. diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index 68d3eb9b5..7e156eaab 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -40,6 +40,7 @@ else: C_JmpBuf* {.importc: "jmp_buf", header: "<setjmp.h>".} = object +type CSighandlerT = proc (a: cint) {.noconv.} when defined(windows): const SIGABRT* = cint(22) @@ -48,6 +49,7 @@ when defined(windows): SIGINT* = cint(2) SIGSEGV* = cint(11) SIGTERM = cint(15) + SIG_DFL* = cast[CSighandlerT](0) elif defined(macosx) or defined(linux) or defined(freebsd) or defined(openbsd) or defined(netbsd) or defined(solaris) or defined(dragonfly) or defined(nintendoswitch) or defined(genode) or @@ -60,6 +62,7 @@ elif defined(macosx) or defined(linux) or defined(freebsd) or SIGSEGV* = cint(11) SIGTERM* = cint(15) SIGPIPE* = cint(13) + SIG_DFL* = cast[CSighandlerT](0) elif defined(haiku): const SIGABRT* = cint(6) @@ -69,6 +72,7 @@ elif defined(haiku): SIGSEGV* = cint(11) SIGTERM* = cint(15) SIGPIPE* = cint(7) + SIG_DFL* = cast[CSighandlerT](0) else: when NoFakeVars: {.error: "SIGABRT not ported to your platform".} @@ -79,6 +83,7 @@ else: SIGABRT* {.importc: "SIGABRT", nodecl.}: cint SIGFPE* {.importc: "SIGFPE", nodecl.}: cint SIGILL* {.importc: "SIGILL", nodecl.}: cint + SIG_DFL* {.importc: "SIG_DFL", nodecl.}: CSighandlerT when defined(macosx) or defined(linux): var SIGPIPE* {.importc: "SIGPIPE", nodecl.}: cint @@ -105,9 +110,9 @@ else: proc c_setjmp*(jmpb: C_JmpBuf): cint {. header: "<setjmp.h>", importc: "setjmp".} -type CSighandlerT = proc (a: cint) {.noconv.} -proc c_signal*(sign: cint, handler: proc (a: cint) {.noconv.}): CSighandlerT {. +proc c_signal*(sign: cint, handler: CSighandlerT): CSighandlerT {. importc: "signal", header: "<signal.h>", discardable.} +proc c_raise*(sign: cint): cint {.importc: "raise", header: "<signal.h>".} type CFile {.importc: "FILE", header: "<stdio.h>", diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index dbb39f536..19bf8911d 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -643,7 +643,17 @@ when not defined(noSignalHandler) and not defined(useNimRtl): # unless there's a good reason to use cstring in signal handler to avoid # using gc? showErrorMessage(msg, msg.len) - quit(1) # always quit when SIGABRT + + when defined(posix): + # reset the signal handler to OS default + c_signal(sign, SIG_DFL) + + # re-raise the signal, which will arrive once this handler exit. + # this lets the OS perform actions like core dumping and will + # also return the correct exit code to the shell. + discard c_raise(sign) + else: + quit(1) proc registerSignalHandler() = c_signal(SIGINT, signalHandler) diff --git a/tests/system/tsigexitcode.nim b/tests/system/tsigexitcode.nim new file mode 100644 index 000000000..6922cb8eb --- /dev/null +++ b/tests/system/tsigexitcode.nim @@ -0,0 +1,20 @@ +discard """ + joinable: false + disabled: windows +""" + +import os, osproc, posix, strutils + +proc main() = + if paramCount() > 0: + let signal = cint parseInt paramStr(1) + discard posix.raise(signal) + else: + # synchronize this list with lib/system/except.nim:registerSignalHandler() + let fatalSigs = [SIGINT, SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, + SIGPIPE] + for s in fatalSigs: + let (_, exitCode) = execCmdEx(quoteShellCommand [getAppFilename(), $s]) + doAssert exitCode == 128 + s, "mismatched exit code for signal " & $s + +main() |