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
parent 95664e1524
commit ccc0667c29
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
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`.

View File

@@ -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>",

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
# 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)

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