diff --git a/CHANGELOG.md b/CHANGELOG.md index aebb8a8cc..1a7850f58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +**Fixes**: + +- Fix `CHAIN_AT_START` handler strategy crashing when the chained handler resets the signal handler and re-raises. ([#1572](https://github.com/getsentry/sentry-native/pull/1572)) + ## 0.13.2 **Features**: diff --git a/src/backends/sentry_backend_inproc.c b/src/backends/sentry_backend_inproc.c index 6efd2ad47..0fed68d46 100644 --- a/src/backends/sentry_backend_inproc.c +++ b/src/backends/sentry_backend_inproc.c @@ -25,6 +25,7 @@ #include #ifdef SENTRY_PLATFORM_UNIX # include +# include #endif #include @@ -1563,6 +1564,14 @@ process_ucontext(const sentry_ucontext_t *uctx) uintptr_t ip = get_instruction_pointer(uctx); uintptr_t sp = get_stack_pointer(uctx); + // Mask the signal so SA_NODEFER doesn't let re-raises from the chained + // handler to kill the process before we regain control. + sigset_t mask, old_mask; + sigemptyset(&mask); + sigaddset(&mask, uctx->signum); + // raw syscall to bypass libsigchain on Android + syscall(SYS_rt_sigprocmask, SIG_BLOCK, &mask, &old_mask, _NSIG / 8); + // invoke the previous handler (typically the CLR/Mono // signal-to-managed-exception handler) invoke_signal_handler( @@ -1578,6 +1587,20 @@ process_ucontext(const sentry_ucontext_t *uctx) return; } + // restore our handler + struct sigaction current; + sigaction(uctx->signum, NULL, ¤t); + if (current.sa_handler == SIG_DFL) { + sigaction(uctx->signum, &g_sigaction, NULL); + } + + // consume pending signal + struct timespec timeout = { 0, 0 }; + syscall(SYS_rt_sigtimedwait, &mask, NULL, &timeout, _NSIG / 8); + + // unmask + syscall(SYS_rt_sigprocmask, SIG_SETMASK, &old_mask, NULL, _NSIG / 8); + // return from runtime handler; continue processing the crash on the // signal thread until the worker takes over }