summaryrefslogtreecommitdiff
path: root/src/pal
diff options
context:
space:
mode:
authorJan Vorlicek <janvorli@microsoft.com>2019-06-17 23:13:33 +0200
committerGitHub <noreply@github.com>2019-06-17 23:13:33 +0200
commit4f6cc4aff1356802f04a7d6bb7a40c1642f7e96e (patch)
tree7eccb6095896c688b31261f82dc8f11fea98c88c /src/pal
parent57a6eb69b3d6005962ad2ae48db18dff268aff56 (diff)
downloadcoreclr-4f6cc4aff1356802f04a7d6bb7a40c1642f7e96e.tar.gz
coreclr-4f6cc4aff1356802f04a7d6bb7a40c1642f7e96e.tar.bz2
coreclr-4f6cc4aff1356802f04a7d6bb7a40c1642f7e96e.zip
Enable running SIGSEGV handler on non-alternate stack (#25196)
When a third party library that someone loads into a coreclr process registers its own SIGSEGV handler and then chain-calls coreclr SIGSEGV handler on a non-alternate stack, coreclr would currently crash. This fix enables it to execute the SIGSEGV handler on the non-alternate stack (original stack of the interrupted thread) in such case. The disadvantage is that stack overflow would lead to silent crash in such a case, but we cannot do anything about it.
Diffstat (limited to 'src/pal')
-rw-r--r--src/pal/src/exception/signal.cpp30
1 files changed, 27 insertions, 3 deletions
diff --git a/src/pal/src/exception/signal.cpp b/src/pal/src/exception/signal.cpp
index df5a5f22a4..fbd94a886b 100644
--- a/src/pal/src/exception/signal.cpp
+++ b/src/pal/src/exception/signal.cpp
@@ -389,6 +389,28 @@ extern "C" void signal_handler_worker(int code, siginfo_t *siginfo, void *contex
/*++
Function :
+ IsRunningOnAlternateStack
+
+ Detects if the current signal handlers is running on an alternate stack
+
+Parameters :
+ The context of the signal
+
+Return :
+ true if we are running on an alternate stack
+
+--*/
+bool IsRunningOnAlternateStack(void *context)
+{
+ stack_t *signalStack = &((native_context_t *)context)->uc_stack;
+ // Check if the signalStack local variable address is within the alternate stack range. If it is not,
+ // then either the alternate stack was not installed at all or the current method is not running on it.
+ void* alternateStackEnd = (char *)signalStack->ss_sp + signalStack->ss_size;
+ return ((signalStack->ss_flags & SS_DISABLE) == 0) && (signalStack->ss_sp <= &signalStack) && (&signalStack < alternateStackEnd);
+}
+
+/*++
+Function :
sigsegv_handler
handle SIGSEGV signal (EXCEPTION_ACCESS_VIOLATION, others)
@@ -417,10 +439,10 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
// Now that we know the SIGSEGV didn't happen due to a stack overflow, execute the common
// hardware signal handler on the original stack.
- // Establish a return point in case the common_signal_handler returns
-
- if (GetCurrentPalThread())
+ if (GetCurrentPalThread() && IsRunningOnAlternateStack(context))
{
+ // Establish a return point in case the common_signal_handler returns
+
volatile bool contextInitialization = true;
void *ptr = alloca(sizeof(SignalHandlerWorkerReturnPoint) + alignof(SignalHandlerWorkerReturnPoint) - 1);
@@ -443,6 +465,8 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
}
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.