summaryrefslogtreecommitdiffstats
path: root/src/sighook.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sighook.c')
-rw-r--r--src/sighook.c45
1 files changed, 37 insertions, 8 deletions
diff --git a/src/sighook.c b/src/sighook.c
index 6fd4c86..b3ac711 100644
--- a/src/sighook.c
+++ b/src/sighook.c
@@ -32,6 +32,10 @@
#include <stdlib.h>
#include <unistd.h>
+#if __linux__
+# include <sys/syscall.h>
+#endif
+
// NetBSD opens a file descriptor for each sem_init()
#if defined(_POSIX_SEMAPHORES) && !__NetBSD__
# define BFS_POSIX_SEMAPHORES _POSIX_SEMAPHORES
@@ -338,22 +342,31 @@ static const int FATAL_SIGNALS[] = {
SIGHUP,
SIGILL,
SIGINT,
+#ifdef SIGIO
+ SIGIO,
+#endif
SIGPIPE,
- SIGQUIT,
- SIGSEGV,
- SIGTERM,
- SIGUSR1,
- SIGUSR2,
#ifdef SIGPOLL
SIGPOLL,
#endif
#ifdef SIGPROF
SIGPROF,
#endif
+#ifdef SIGPWR
+ SIGPWR,
+#endif
+ SIGQUIT,
+ SIGSEGV,
+#ifdef SIGSTKFLT
+ SIGSTKFLT,
+#endif
#ifdef SIGSYS
SIGSYS,
#endif
+ SIGTERM,
SIGTRAP,
+ SIGUSR1,
+ SIGUSR2,
#ifdef SIGVTALRM
SIGVTALRM,
#endif
@@ -385,7 +398,9 @@ static bool is_fatal(int sig) {
/** Reraise a fatal signal. */
_noreturn
-static void reraise(int sig) {
+static void reraise(siginfo_t *info) {
+ int sig = info->si_signo;
+
// Restore the default signal action
if (signal(sig, SIG_DFL) == SIG_ERR) {
goto fail;
@@ -399,6 +414,13 @@ static void reraise(int sig) {
goto fail;
}
+#if __linux__
+ // On Linux, try to re-raise the exact siginfo_t (since 3.9, a process can
+ // signal itself with any siginfo_t)
+ pid_t tid = syscall(SYS_gettid);
+ syscall(SYS_rt_tgsigqueueinfo, getpid(), tid, sig, info);
+#endif
+
raise(sig);
fail:
abort();
@@ -452,10 +474,17 @@ static void sigdispatch(int sig, siginfo_t *info, void *context) {
// to die "correctly" (e.g. with a core dump pointing at the faulting
// instruction, not reraise()).
if (is_fault(info)) {
+ // On macOS, we cannot reliably distinguish between faults and
+ // asynchronous signals. For example, pkill -SEGV bfs will
+ // result in si_code == SEGV_ACCERR. So we always re-raise the
+ // signal, because just returning would cause us to ignore
+ // asynchronous SIG{BUS,ILL,SEGV}.
+#if !__APPLE__
if (signal(sig, SIG_DFL) != SIG_ERR) {
return;
}
- reraise(sig);
+#endif
+ reraise(info);
}
// https://pubs.opengroup.org/onlinepubs/9799919799/functions/V2_chap02.html#tag_16_04_04
@@ -475,7 +504,7 @@ static void sigdispatch(int sig, siginfo_t *info, void *context) {
if (!(flags & SH_CONTINUE) && is_fatal(sig)) {
list = siglist(0);
run_hooks(list, sig, info);
- reraise(sig);
+ reraise(info);
}
errno = error;