From 9230f2b846a670b2438fe583486a5c0f6430f251 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Fri, 16 Aug 2024 14:30:18 +0200 Subject: [PATCH] Fix stack overflow handling with SuperPMI (#106495) * Fix stack overflow handling with SuperPMI When SuperPMI shared library is loaded last, its SIGSEGV handler is the first one that's executed. But since there is no coreclr runtime handler installed for it, it returns from the SwitchStackAndExecuteHandler in case of SIGSEGV. The remaining code in the SIGSEGV handler was not expecting that and thought that there was no stack overflow and attempted to run the hardware exception handler on the original stack of the thread, which obviously crashed since the original stack overflowed. The fix is to make sure that we only call the previously registered signal handler in this case. Close #84911 * PR feedback --- src/coreclr/pal/src/exception/signal.cpp | 39 +++++++++++++----------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/coreclr/pal/src/exception/signal.cpp b/src/coreclr/pal/src/exception/signal.cpp index 3b38ca2817dbc..4a5cfac1d41ea 100644 --- a/src/coreclr/pal/src/exception/signal.cpp +++ b/src/coreclr/pal/src/exception/signal.cpp @@ -641,6 +641,9 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context) { PROCAbort(SIGSEGV, siginfo); } + + // The current executable (shared library) doesn't have hardware exception handler installed or opted to not to + // handle it. So this handler will invoke the previously installed handler at the end of this function. } else { @@ -648,27 +651,29 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context) PROCAbort(SIGSEGV, siginfo); } } - - // Now that we know the SIGSEGV didn't happen due to a stack overflow, execute the common - // hardware signal handler on the original stack. - - if (GetCurrentPalThread() && IsRunningOnAlternateStack(context)) + else { - if (SwitchStackAndExecuteHandler(code, siginfo, context, 0 /* sp */)) // sp == 0 indicates execution on the original stack + // Now that we know the SIGSEGV didn't happen due to a stack overflow, execute the common + // hardware signal handler on the original stack. + + if (GetCurrentPalThread() && IsRunningOnAlternateStack(context)) { - return; + if (SwitchStackAndExecuteHandler(code, siginfo, context, 0 /* sp */)) // sp == 0 indicates execution on the original stack + { + return; + } } - } - else - { - // The code flow gets here when the signal handler is not running on an alternate stack or when it wasn't created - // by coreclr. In both cases, we execute the common_signal_handler directly. - // If thread isn't created by coreclr and has alternate signal stack GetCurrentPalThread() will return NULL too. - // But since in this case we don't handle hardware exceptions (IsSafeToHandleHardwareException returns false) - // we can call common_signal_handler on the alternate stack. - if (common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr)) + else { - return; + // The code flow gets here when the signal handler is not running on an alternate stack or when it wasn't created + // by coreclr. In both cases, we execute the common_signal_handler directly. + // If thread isn't created by coreclr and has alternate signal stack GetCurrentPalThread() will return NULL too. + // But since in this case we don't handle hardware exceptions (IsSafeToHandleHardwareException returns false) + // we can call common_signal_handler on the alternate stack. + if (common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr)) + { + return; + } } } }