summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2024-11-23 15:39:03 -0500
committerTavian Barnes <tavianator@tavianator.com>2024-11-23 15:43:40 -0500
commitaecdabb625841052a68fd3b5510c56b138693c9a (patch)
tree8aef3432abeb92ceb408eafd10d649ed39531b7e
parentf7b813fdffb6c744cd443c6d5f81e6918b20f1ac (diff)
downloadbfs-aecdabb625841052a68fd3b5510c56b138693c9a.tar.xz
sighook: Return instead of re-raising for faults
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
-rw-r--r--src/sighook.c16
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);
}