diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2024-11-23 15:39:03 -0500 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2024-11-23 15:43:40 -0500 |
commit | aecdabb625841052a68fd3b5510c56b138693c9a (patch) | |
tree | 8aef3432abeb92ceb408eafd10d649ed39531b7e /src/sighook.c | |
parent | f7b813fdffb6c744cd443c6d5f81e6918b20f1ac (diff) | |
download | bfs-aecdabb625841052a68fd3b5510c56b138693c9a.tar.xz |
This makes the death look exactly like it would if we didn't handle the
signal at all. Coredumps will point at the right instruction, segfaults
will get logged in dmesg again, etc.
Technically POSIX says this is undefined, but if we get a fault, we've
already done something undefined anyway ;)
Link: https://github.com/rust-lang/rust/issues/26458
Diffstat (limited to 'src/sighook.c')
-rw-r--r-- | src/sighook.c | 16 |
1 files changed, 11 insertions, 5 deletions
diff --git a/src/sighook.c b/src/sighook.c index cd17e42..a294206 100644 --- a/src/sighook.c +++ b/src/sighook.c @@ -425,13 +425,19 @@ static enum sigflags run_hooks(struct siglist *list, int sig, siginfo_t *info) { /** Dispatches a signal to the registered handlers. */ static void sigdispatch(int sig, siginfo_t *info, void *context) { - // https://pubs.opengroup.org/onlinepubs/9799919799/functions/V2_chap02.html#tag_16_04_03_03 + // If we get a fault (e.g. a "real" SIGSEGV, not something like + // kill(..., SIGSEGV)), don't try to run signal hooks, since we could be + // in an arbitrarily corrupted state. // - // The behavior of a process is undefined after it returns normally - // from a signal-catching function for a SIGBUS, SIGFPE, SIGILL, or - // SIGSEGV signal that was not generated by kill(), sigqueue(), or - // raise(). + // POSIX says that returning normally from a signal handler for a fault + // is undefined. But in practice, it's better to uninstall the handler + // and return, which will re-run the faulting instruction and cause us + // to die "correctly" (e.g. with a core dump pointing at the faulting + // instruction, not reraise()). if (is_fault(info)) { + if (signal(sig, SIG_DFL) != SIG_ERR) { + return; + } reraise(sig); } |