Fix chained hardware exception handling on Unix (#12344)
authorJan Vorlicek <janvorli@microsoft.com>
Sat, 17 Jun 2017 12:13:39 +0000 (14:13 +0200)
committerGitHub <noreply@github.com>
Sat, 17 Jun 2017 12:13:39 +0000 (14:13 +0200)
There is an issue when hardware exception occurs while handling another hardware exception. In such case,
the exception unwinding ends up in an infinite loop. It is caused by the kernel reusing the same location
for signal handler context.

The fix is to use a windows style context local variable in the common_signal_handler that contains
the right context - it is the original signal context converted to windows style context.

src/pal/src/exception/seh-unwind.cpp
src/pal/src/exception/signal.cpp

index 360ea3e..f1f25b0 100644 (file)
@@ -266,8 +266,8 @@ BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextP
     // cannot cross on some systems.
     if ((void*)curPc == g_SEHProcessExceptionReturnAddress)
     {
-        CONTEXT* nativeContext = *(CONTEXT**)(CONTEXTGetFP(context) + g_common_signal_handler_context_locvar_offset);
-        memcpy_s(context, sizeof(CONTEXT), nativeContext, sizeof(CONTEXT));
+        CONTEXT* signalContext = (CONTEXT*)(CONTEXTGetFP(context) + g_common_signal_handler_context_locvar_offset);
+        memcpy_s(context, sizeof(CONTEXT), signalContext, sizeof(CONTEXT));
 
         return TRUE;
     }
index 6a046bd..b580ba4 100644 (file)
@@ -761,12 +761,13 @@ __attribute__((noinline))
 static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext, int numParams, ...)
 {
     sigset_t signal_set;
+    CONTEXT signalContextRecord;
     CONTEXT *contextRecord;
     EXCEPTION_RECORD *exceptionRecord;
     native_context_t *ucontext;
 
     ucontext = (native_context_t *)sigcontext;
-    g_common_signal_handler_context_locvar_offset = (int)((char*)&contextRecord - (char*)__builtin_frame_address(0));
+    g_common_signal_handler_context_locvar_offset = (int)((char*)&signalContextRecord - (char*)__builtin_frame_address(0));
 
     AllocateExceptionRecords(&exceptionRecord, &contextRecord);
 
@@ -809,6 +810,9 @@ static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext
     }
 
     contextRecord->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
+
+    memcpy_s(&signalContextRecord, sizeof(CONTEXT), contextRecord, sizeof(CONTEXT));
+
     // The exception object takes ownership of the exceptionRecord and contextRecord
     PAL_SEHException exception(exceptionRecord, contextRecord);