Skip to content

Commit c9b8b43

Browse files
committed
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 dotnet#84911
1 parent a842025 commit c9b8b43

File tree

1 file changed

+24
-17
lines changed

1 file changed

+24
-17
lines changed

src/coreclr/pal/src/exception/signal.cpp

+24-17
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,8 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
621621

622622
// If the failure address is at most one page above or below the stack pointer,
623623
// we have a stack overflow.
624-
if ((failureAddress - (sp - GetVirtualPageSize())) < 2 * GetVirtualPageSize())
624+
bool isStackOverflow = (failureAddress - (sp - GetVirtualPageSize())) < 2 * GetVirtualPageSize();
625+
if (isStackOverflow)
625626
{
626627
if (GetCurrentPalThread())
627628
{
@@ -641,6 +642,9 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
641642
{
642643
PROCAbort(SIGSEGV, siginfo);
643644
}
645+
646+
// The current executable (shared library) doesn't have hardware exception handler installed or opted to not to
647+
// handle it. So this handler will invoke the previously installed handler at the end of this function.
644648
}
645649
else
646650
{
@@ -649,26 +653,29 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
649653
}
650654
}
651655

652-
// Now that we know the SIGSEGV didn't happen due to a stack overflow, execute the common
653-
// hardware signal handler on the original stack.
654-
655-
if (GetCurrentPalThread() && IsRunningOnAlternateStack(context))
656+
if (!isStackOverflow)
656657
{
657-
if (SwitchStackAndExecuteHandler(code, siginfo, context, 0 /* sp */)) // sp == 0 indicates execution on the original stack
658+
// Now that we know the SIGSEGV didn't happen due to a stack overflow, execute the common
659+
// hardware signal handler on the original stack.
660+
661+
if (GetCurrentPalThread() && IsRunningOnAlternateStack(context))
658662
{
659-
return;
663+
if (SwitchStackAndExecuteHandler(code, siginfo, context, 0 /* sp */)) // sp == 0 indicates execution on the original stack
664+
{
665+
return;
666+
}
660667
}
661-
}
662-
else
663-
{
664-
// The code flow gets here when the signal handler is not running on an alternate stack or when it wasn't created
665-
// by coreclr. In both cases, we execute the common_signal_handler directly.
666-
// If thread isn't created by coreclr and has alternate signal stack GetCurrentPalThread() will return NULL too.
667-
// But since in this case we don't handle hardware exceptions (IsSafeToHandleHardwareException returns false)
668-
// we can call common_signal_handler on the alternate stack.
669-
if (common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr))
668+
else
670669
{
671-
return;
670+
// The code flow gets here when the signal handler is not running on an alternate stack or when it wasn't created
671+
// by coreclr. In both cases, we execute the common_signal_handler directly.
672+
// If thread isn't created by coreclr and has alternate signal stack GetCurrentPalThread() will return NULL too.
673+
// But since in this case we don't handle hardware exceptions (IsSafeToHandleHardwareException returns false)
674+
// we can call common_signal_handler on the alternate stack.
675+
if (common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr))
676+
{
677+
return;
678+
}
672679
}
673680
}
674681
}

0 commit comments

Comments
 (0)