system/excpt: let the OS handle termination on signal (#16712)

This commit is contained in:
alaviss 2021-02-19 08:29:21 +00:00 • committed by GitHub
commit ccc0667c29
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 46 additions and 3 deletions

View file

@ -159,6 +159,14 @@ provided by the operating system.
`ValueError` when the real command line is not available. `parseopt` was `ValueError` when the real command line is not available. `parseopt` was
previously excluded from `prelude` for JS, as it could not be imported. 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 ## Language changes
- `nimscript` now handles `except Exception as e`. - `nimscript` now handles `except Exception as e`.

View file

@ -40,6 +40,7 @@ else:
C_JmpBuf* {.importc: "jmp_buf", header: "<setjmp.h>".} = object C_JmpBuf* {.importc: "jmp_buf", header: "<setjmp.h>".} = object
type CSighandlerT = proc (a: cint) {.noconv.}
when defined(windows): when defined(windows):
const const
SIGABRT* = cint(22) SIGABRT* = cint(22)
@ -48,6 +49,7 @@ when defined(windows):
SIGINT* = cint(2) SIGINT* = cint(2)
SIGSEGV* = cint(11) SIGSEGV* = cint(11)
SIGTERM = cint(15) SIGTERM = cint(15)
SIG_DFL* = cast[CSighandlerT](0)
elif defined(macosx) or defined(linux) or defined(freebsd) or elif defined(macosx) or defined(linux) or defined(freebsd) or
defined(openbsd) or defined(netbsd) or defined(solaris) or defined(openbsd) or defined(netbsd) or defined(solaris) or
defined(dragonfly) or defined(nintendoswitch) or defined(genode) 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) SIGSEGV* = cint(11)
SIGTERM* = cint(15) SIGTERM* = cint(15)
SIGPIPE* = cint(13) SIGPIPE* = cint(13)
SIG_DFL* = cast[CSighandlerT](0)
elif defined(haiku): elif defined(haiku):
const const
SIGABRT* = cint(6) SIGABRT* = cint(6)
@ -69,6 +72,7 @@ elif defined(haiku):
SIGSEGV* = cint(11) SIGSEGV* = cint(11)
SIGTERM* = cint(15) SIGTERM* = cint(15)
SIGPIPE* = cint(7) SIGPIPE* = cint(7)
SIG_DFL* = cast[CSighandlerT](0)
else: else:
when NoFakeVars: when NoFakeVars:
{.error: "SIGABRT not ported to your platform".} {.error: "SIGABRT not ported to your platform".}
@ -79,6 +83,7 @@ else:
SIGABRT* {.importc: "SIGABRT", nodecl.}: cint SIGABRT* {.importc: "SIGABRT", nodecl.}: cint
SIGFPE* {.importc: "SIGFPE", nodecl.}: cint SIGFPE* {.importc: "SIGFPE", nodecl.}: cint
SIGILL* {.importc: "SIGILL", nodecl.}: cint SIGILL* {.importc: "SIGILL", nodecl.}: cint
SIG_DFL* {.importc: "SIG_DFL", nodecl.}: CSighandlerT
when defined(macosx) or defined(linux): when defined(macosx) or defined(linux):
var SIGPIPE* {.importc: "SIGPIPE", nodecl.}: cint var SIGPIPE* {.importc: "SIGPIPE", nodecl.}: cint
@ -105,9 +110,9 @@ else:
proc c_setjmp*(jmpb: C_JmpBuf): cint {. proc c_setjmp*(jmpb: C_JmpBuf): cint {.
header: "<setjmp.h>", importc: "setjmp".} header: "<setjmp.h>", importc: "setjmp".}
type CSighandlerT = proc (a: cint) {.noconv.} proc c_signal*(sign: cint, handler: CSighandlerT): CSighandlerT {.
proc c_signal*(sign: cint, handler: proc (a: cint) {.noconv.}): CSighandlerT {.
importc: "signal", header: "<signal.h>", discardable.} importc: "signal", header: "<signal.h>", discardable.}
proc c_raise*(sign: cint): cint {.importc: "raise", header: "<signal.h>".}
type type
CFile {.importc: "FILE", header: "<stdio.h>", CFile {.importc: "FILE", header: "<stdio.h>",

View file

@ -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 # unless there's a good reason to use cstring in signal handler to avoid
# using gc? # using gc?
showErrorMessage(msg, msg.len) 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() = proc registerSignalHandler() =
c_signal(SIGINT, signalHandler) c_signal(SIGINT, signalHandler)

View file

@ -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()