diff --git a/src/mono/mono/mini/mini-posix.c b/src/mono/mono/mini/mini-posix.c index be8f83d396872d..c0d79661aa8289 100644 --- a/src/mono/mono/mini/mini-posix.c +++ b/src/mono/mono/mini/mini-posix.c @@ -188,7 +188,7 @@ save_old_signal_handler (int signo, struct sigaction *old_action) * * Call the original signal handler for the signal given by the arguments, which * should be the same as for a signal handler. Returns TRUE if the original handler - * was called, false otherwise. + * was called, false otherwise. NOTE: sigaction.sa_handler == SIG_DFL handlers are not considered. */ gboolean MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal) @@ -196,6 +196,7 @@ MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal) int signal = MONO_SIG_HANDLER_GET_SIGNO (); struct sigaction *saved_handler = (struct sigaction *)get_saved_signal_handler (signal); + // Ignores chaining to default signal handlers i.e. when saved_handler->sa_handler == SIG_DFL if (saved_handler && saved_handler->sa_handler) { if (!(saved_handler->sa_flags & SA_SIGINFO)) { saved_handler->sa_handler (signal); @@ -209,6 +210,27 @@ MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal) return FALSE; } + +/* + * mono_chain_signal_to_default_sigsegv_handler: + * + * Call the original SIGSEGV signal handler in cases when the original handler is + * sigaction.sa_handler == SIG_DFL. This is used to propagate the crash to the OS. + */ +void +mono_chain_signal_to_default_sigsegv_handler (void) +{ + struct sigaction *saved_handler = (struct sigaction *)get_saved_signal_handler (SIGSEGV); + + if (saved_handler && saved_handler->sa_handler == SIG_DFL) { + sigaction (SIGSEGV, saved_handler, NULL); + raise (SIGSEGV); + } else { + g_async_safe_printf ("\nFailed to chain SIGSEGV signal to the default handler.\n"); + } +} + + MONO_SIG_HANDLER_FUNC (static, sigabrt_signal_handler) { MonoJitInfo *ji = NULL; @@ -348,8 +370,14 @@ add_signal_handler (int signo, MonoSignalHandler handler, int flags) /* if there was already a handler in place for this signal, store it */ if (! (previous_sa.sa_flags & SA_SIGINFO) && - (SIG_DFL == previous_sa.sa_handler)) { - /* it there is no sa_sigaction function and the sa_handler is default, we can safely ignore this */ + (SIG_DFL == previous_sa.sa_handler) && signo != SIGSEGV) { + /* + * If there is no sa_sigaction function and the sa_handler is default, + * it means the currently registered handler for this signal is the default one. + * For signal chaining, we need to store the default SIGSEGV handler so that the crash + * is properly propagated, while default handlers for other signals are ignored and + * are not considered. + */ } else { if (mono_do_signal_chaining) save_old_signal_handler (signo, &previous_sa); diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c index 0318c3d1689bcc..10815aceaf996c 100644 --- a/src/mono/mono/mini/mini-runtime.c +++ b/src/mono/mono/mini/mini-runtime.c @@ -3895,7 +3895,8 @@ MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler) mono_handle_native_crash (mono_get_signame (SIGSEGV), &mctx, (MONO_SIG_HANDLER_INFO_TYPE*)info); if (mono_do_crash_chaining) { - mono_chain_signal (MONO_SIG_HANDLER_PARAMS); + if (!mono_chain_signal (MONO_SIG_HANDLER_PARAMS)) + mono_chain_signal_to_default_sigsegv_handler (); return; } } @@ -3905,7 +3906,8 @@ MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler) } else { mono_handle_native_crash (mono_get_signame (SIGSEGV), &mctx, (MONO_SIG_HANDLER_INFO_TYPE*)info); if (mono_do_crash_chaining) { - mono_chain_signal (MONO_SIG_HANDLER_PARAMS); + if (!mono_chain_signal (MONO_SIG_HANDLER_PARAMS)) + mono_chain_signal_to_default_sigsegv_handler (); return; } } diff --git a/src/mono/mono/mini/mini-runtime.h b/src/mono/mono/mini/mini-runtime.h index 19826d4c3f86b1..dd07918269cf4c 100644 --- a/src/mono/mono/mini/mini-runtime.h +++ b/src/mono/mono/mini/mini-runtime.h @@ -673,6 +673,7 @@ void MONO_SIG_HANDLER_SIGNATURE (mono_crashing_signal_handler) ; void MONO_SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler); void MONO_SIG_HANDLER_SIGNATURE (mono_sigint_signal_handler) ; gboolean MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal); +void mono_chain_signal_to_default_sigsegv_handler (void); #if defined (HOST_WASM) diff --git a/src/mono/mono/mini/mini-wasm.c b/src/mono/mono/mini/mini-wasm.c index 21174bec0d860d..00e97c95f4f2e1 100644 --- a/src/mono/mono/mini/mini-wasm.c +++ b/src/mono/mono/mini/mini-wasm.c @@ -576,6 +576,12 @@ MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal) return FALSE; } +void +mono_chain_signal_to_default_sigsegv_handler (void) +{ + g_error ("mono_chain_signal_to_default_sigsegv_handler not supported on WASM"); +} + gboolean mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoThreadInfo *info, void *sigctx) { diff --git a/src/mono/mono/mini/mini-windows.c b/src/mono/mono/mini/mini-windows.c index f5d81c537a6910..b049428de79ce4 100644 --- a/src/mono/mono/mini/mini-windows.c +++ b/src/mono/mono/mini/mini-windows.c @@ -252,6 +252,12 @@ MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal) return TRUE; } +void +mono_chain_signal_to_default_sigsegv_handler (void) +{ + g_error ("mono_chain_signal_to_default_sigsegv_handler not supported on Windows"); +} + #if !HAVE_EXTERN_DEFINED_NATIVE_CRASH_HANDLER #ifndef MONO_CROSS_COMPILE void