diff --git a/Common/ExceptionHandlerSetup.cpp b/Common/ExceptionHandlerSetup.cpp index e26b9c7d85..2cdb36a87f 100644 --- a/Common/ExceptionHandlerSetup.cpp +++ b/Common/ExceptionHandlerSetup.cpp @@ -312,6 +312,28 @@ static struct sigaction old_sa_bus; static stack_t old_signal_stack{}; static bool old_signal_stack_valid = false; +// Hand the signal on to whatever was installed before us. Returning from a fault handler just +// re-runs the faulting instruction, so for anything we can't deal with this is the only exit +// that isn't an infinite loop. +static void ChainToPreviousHandler(int sig, siginfo_t *info, void *raw_context) { + struct sigaction *old_sa = sig == SIGSEGV ? &old_sa_segv : &old_sa_bus; + // Per the sigaction man page: with SA_SIGINFO it's sa_sigaction, otherwise sa_handler is + // SIG_DFL, SIG_IGN, or a handler pointer. + if (old_sa->sa_flags & SA_SIGINFO) { + old_sa->sa_sigaction(sig, info, raw_context); + return; + } + if (old_sa->sa_handler == SIG_DFL) { + signal(sig, SIG_DFL); + return; + } + if (old_sa->sa_handler == SIG_IGN) { + // Ignore signal + return; + } + old_sa->sa_handler(sig); +} + static void sigsegv_handler(int sig, siginfo_t* info, void* raw_context) { if (sig != SIGSEGV && sig != SIGBUS) { // We are not interested in other signals - handle it as usual. @@ -320,7 +342,11 @@ static void sigsegv_handler(int sig, siginfo_t* info, void* raw_context) { ucontext_t* context = (ucontext_t*)raw_context; int sicode = info->si_code; if (sicode != SEGV_MAPERR && sicode != SEGV_ACCERR) { - // Huh? Return. + // Not an address fault we can do anything with - an MTE, protection-key or shadow + // stack fault, or a signal sent with kill(). Returning here would re-run the + // faulting instruction forever at 100% CPU, and would also swallow the signal from + // whatever was installed before us (a crash reporter, say). + ChainToPreviousHandler(sig, info, raw_context); return; } uintptr_t bad_address = (uintptr_t)info->si_addr; @@ -346,26 +372,7 @@ static void sigsegv_handler(int sig, siginfo_t* info, void* raw_context) { // SIG_IGN: The signal is ignored // Any other value is a function pointer to a signal handler - struct sigaction* old_sa; - if (sig == SIGSEGV) { - old_sa = &old_sa_segv; - } else { - old_sa = &old_sa_bus; - } - - if (old_sa->sa_flags & SA_SIGINFO) { - old_sa->sa_sigaction(sig, info, raw_context); - return; - } - if (old_sa->sa_handler == SIG_DFL) { - signal(sig, SIG_DFL); - return; - } - if (old_sa->sa_handler == SIG_IGN) { - // Ignore signal - return; - } - old_sa->sa_handler(sig); + ChainToPreviousHandler(sig, info, raw_context); } }