Port to 3.0 - Fix WSL alternate stack check (#25980)
authorJan Vorlicek <janvorli@microsoft.com>
Wed, 7 Aug 2019 16:15:14 +0000 (18:15 +0200)
committerWilliam Godbe <wigodbe@microsoft.com>
Wed, 7 Aug 2019 16:15:14 +0000 (09:15 -0700)
On WSL, the alternate stack check in sigsegv_handler doesn't work. The
uc_stack members are always zero no matter whether the handler is
executed on an alternate or default stack. So the check to detect
whether we are running on an alternate stack or not is always returning
false on WSL and it prevents NULL reference exceptions from being
handled.
The fix is to introduce an env variable COMPlus_EnableAlternateStackCheck
that can be used to enable the alternate stack check. By default, the
sigsegv_handler is considered to always run on an alternate stack.

src/pal/src/exception/signal.cpp
src/pal/src/include/pal/signal.hpp

index fbd94a8..7e00483 100644 (file)
@@ -91,7 +91,9 @@ static void restore_signal_and_resend(int code, struct sigaction* action);
 
 #if !HAVE_MACH_EXCEPTIONS
 bool g_registered_signal_handlers = false;
+bool g_enable_alternate_stack_check = false;
 #endif // !HAVE_MACH_EXCEPTIONS
+
 static bool g_registered_sigterm_handler = false;
 
 struct sigaction g_previous_sigterm;
@@ -132,6 +134,11 @@ BOOL SEHInitializeSignals(CorUnix::CPalThread *pthrCurrent, DWORD flags)
     TRACE("Initializing signal handlers\n");
 
 #if !HAVE_MACH_EXCEPTIONS
+
+    char* enableAlternateStackCheck = getenv("COMPlus_EnableAlternateStackCheck");
+
+    g_enable_alternate_stack_check = enableAlternateStackCheck && (strtoul(enableAlternateStackCheck, NULL, 10) != 0);
+
     if (flags & PAL_INITIALIZE_REGISTER_SIGNALS)
     {
         g_registered_signal_handlers = true;
@@ -402,11 +409,25 @@ Return :
 --*/
 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);
+    bool isRunningOnAlternateStack;
+    if (g_enable_alternate_stack_check)
+    {
+        // Note: WSL doesn't return the alternate signal ranges in the uc_stack (the whole structure is zeroed no
+        // matter whether the code is running on an alternate stack or not). So the check would always fail on WSL.
+        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;
+        isRunningOnAlternateStack = ((signalStack->ss_flags & SS_DISABLE) == 0) && (signalStack->ss_sp <= &signalStack) && (&signalStack < alternateStackEnd);
+    }
+    else
+    {
+        // If alternate stack check is disabled, consider always that we are running on an alternate
+        // signal handler stack.
+        isRunningOnAlternateStack = true;
+    }
+
+    return isRunningOnAlternateStack;
 }
 
 /*++
index 9c14d2f..244f161 100644 (file)
@@ -30,6 +30,7 @@ struct SignalHandlerWorkerReturnPoint
 };
 
 extern bool g_registered_signal_handlers;
+extern bool g_enable_alternate_stack_check;
 
 /*++
 Function :