Piotr Caban : ntdll: Add support for exceptions inside termination handlers in __C_specific_handler.

Alexandre Julliard julliard at winehq.org
Thu Aug 18 10:23:24 CDT 2016


Module: wine
Branch: master
Commit: b23de3cd4a2c0ab0fd3f54369a2786e008c79539
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=b23de3cd4a2c0ab0fd3f54369a2786e008c79539

Author: Piotr Caban <piotr at codeweavers.com>
Date:   Wed Aug 17 12:48:13 2016 +0200

ntdll: Add support for exceptions inside termination handlers in __C_specific_handler.

Signed-off-by: Piotr Caban <piotr at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/signal_x86_64.c   | 16 ++++-----
 dlls/ntdll/tests/exception.c | 83 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 91 insertions(+), 8 deletions(-)

diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index e50c8ed..062a40c 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -3787,7 +3787,6 @@ void WINAPI _local_unwind( void *frame, void *target_ip )
     RtlUnwindEx( frame, target_ip, NULL, NULL, &context, NULL );
 }
 
-
 /*******************************************************************
  *		__C_specific_handler (NTDLL.@)
  */
@@ -3804,10 +3803,10 @@ EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec,
 
     if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
     {
-        for (i = 0; i < table->Count; i++)
+        for (i = dispatch->ScopeIndex; i < table->Count; i++)
         {
-            if (context->Rip >= dispatch->ImageBase + table->ScopeRecord[i].BeginAddress &&
-                context->Rip < dispatch->ImageBase + table->ScopeRecord[i].EndAddress)
+            if (dispatch->ControlPc >= dispatch->ImageBase + table->ScopeRecord[i].BeginAddress &&
+                dispatch->ControlPc < dispatch->ImageBase + table->ScopeRecord[i].EndAddress)
             {
                 TERMINATION_HANDLER handler;
 
@@ -3821,6 +3820,7 @@ EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec,
                 }
 
                 handler = (TERMINATION_HANDLER)(dispatch->ImageBase + table->ScopeRecord[i].HandlerAddress);
+                dispatch->ScopeIndex = i+1;
 
                 TRACE( "calling __finally %p frame %lx\n", handler, frame );
                 handler( 1, frame );
@@ -3829,10 +3829,10 @@ EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec,
         return ExceptionContinueSearch;
     }
 
-    for (i = 0; i < table->Count; i++)
+    for (i = dispatch->ScopeIndex; i < table->Count; i++)
     {
-        if (context->Rip >= dispatch->ImageBase + table->ScopeRecord[i].BeginAddress &&
-            context->Rip < dispatch->ImageBase + table->ScopeRecord[i].EndAddress)
+        if (dispatch->ControlPc >= dispatch->ImageBase + table->ScopeRecord[i].BeginAddress &&
+            dispatch->ControlPc < dispatch->ImageBase + table->ScopeRecord[i].EndAddress)
         {
             if (!table->ScopeRecord[i].JumpTarget) continue;
             if (table->ScopeRecord[i].HandlerAddress != EXCEPTION_EXECUTE_HANDLER)
@@ -3856,7 +3856,7 @@ EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec,
             }
             TRACE( "unwinding to target %lx\n", dispatch->ImageBase + table->ScopeRecord[i].JumpTarget );
             RtlUnwindEx( (void *)frame, (char *)dispatch->ImageBase + table->ScopeRecord[i].JumpTarget,
-                         rec, 0, context, dispatch->HistoryTable );
+                         rec, 0, dispatch->ContextRecord, dispatch->HistoryTable );
         }
     }
     return ExceptionContinueSearch;
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index a086436..f1bfee6 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -53,10 +53,37 @@ static NTSTATUS  (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PV
 static BOOL      (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
 
 #if defined(__x86_64__)
+typedef struct
+{
+    ULONG Count;
+    struct
+    {
+        ULONG BeginAddress;
+        ULONG EndAddress;
+        ULONG HandlerAddress;
+        ULONG JumpTarget;
+    } ScopeRecord[1];
+} SCOPE_TABLE;
+
+typedef struct
+{
+    ULONG64               ControlPc;
+    ULONG64               ImageBase;
+    PRUNTIME_FUNCTION     FunctionEntry;
+    ULONG64               EstablisherFrame;
+    ULONG64               TargetIp;
+    PCONTEXT              ContextRecord;
+    void* /*PEXCEPTION_ROUTINE*/ LanguageHandler;
+    PVOID                 HandlerData;
+    PUNWIND_HISTORY_TABLE HistoryTable;
+    ULONG                 ScopeIndex;
+} DISPATCHER_CONTEXT;
+
 static BOOLEAN   (CDECL *pRtlAddFunctionTable)(RUNTIME_FUNCTION*, DWORD, DWORD64);
 static BOOLEAN   (CDECL *pRtlDeleteFunctionTable)(RUNTIME_FUNCTION*);
 static BOOLEAN   (CDECL *pRtlInstallFunctionTableCallback)(DWORD64, DWORD64, DWORD, PGET_RUNTIME_FUNCTION_CALLBACK, PVOID, PCWSTR);
 static PRUNTIME_FUNCTION (WINAPI *pRtlLookupFunctionEntry)(ULONG64, ULONG64*, UNWIND_HISTORY_TABLE*);
+static EXCEPTION_DISPOSITION (WINAPI *p__C_specific_handler)(EXCEPTION_RECORD*, ULONG64, CONTEXT*, DISPATCHER_CONTEXT*);
 #endif
 
 #ifdef __i386__
@@ -1747,6 +1774,59 @@ static void test_dynamic_unwind(void)
 
 }
 
+static int termination_handler_called;
+static void WINAPI termination_handler(ULONG flags, ULONG64 frame)
+{
+    termination_handler_called++;
+
+    ok(flags == 1 || broken(flags == 0x401), "flags = %x\n", flags);
+    ok(frame == 0x1234, "frame = %p\n", (void*)frame);
+}
+
+static void test___C_specific_handler(void)
+{
+    DISPATCHER_CONTEXT dispatch;
+    EXCEPTION_RECORD rec;
+    CONTEXT context;
+    ULONG64 frame;
+    EXCEPTION_DISPOSITION ret;
+    SCOPE_TABLE scope_table;
+
+    if (!p__C_specific_handler)
+    {
+        win_skip("__C_specific_handler not available\n");
+        return;
+    }
+
+    memset(&rec, 0, sizeof(rec));
+    rec.ExceptionFlags = 2; /* EH_UNWINDING */
+    frame = 0x1234;
+    memset(&dispatch, 0, sizeof(dispatch));
+    dispatch.ImageBase = (ULONG_PTR)GetModuleHandleA(NULL);
+    dispatch.ControlPc = dispatch.ImageBase + 0x200;
+    dispatch.HandlerData = &scope_table;
+    dispatch.ContextRecord = &context;
+    scope_table.Count = 1;
+    scope_table.ScopeRecord[0].BeginAddress = 0x200;
+    scope_table.ScopeRecord[0].EndAddress = 0x400;
+    scope_table.ScopeRecord[0].HandlerAddress = (ULONG_PTR)termination_handler-dispatch.ImageBase;
+    scope_table.ScopeRecord[0].JumpTarget = 0;
+    memset(&context, 0, sizeof(context));
+
+    termination_handler_called = 0;
+    ret = p__C_specific_handler(&rec, frame, &context, &dispatch);
+    ok(ret == ExceptionContinueSearch, "__C_specific_handler returned %x\n", ret);
+    ok(termination_handler_called == 1, "termination_handler_called = %d\n",
+            termination_handler_called);
+    ok(dispatch.ScopeIndex == 1, "dispatch.ScopeIndex = %d\n", dispatch.ScopeIndex);
+
+    ret = p__C_specific_handler(&rec, frame, &context, &dispatch);
+    ok(ret == ExceptionContinueSearch, "__C_specific_handler returned %x\n", ret);
+    ok(termination_handler_called == 1, "termination_handler_called = %d\n",
+            termination_handler_called);
+    ok(dispatch.ScopeIndex == 1, "dispatch.ScopeIndex = %d\n", dispatch.ScopeIndex);
+}
+
 #endif  /* __x86_64__ */
 
 #if defined(__i386__) || defined(__x86_64__)
@@ -2267,6 +2347,8 @@ START_TEST(exception)
                                                                  "RtlInstallFunctionTableCallback" );
     pRtlLookupFunctionEntry            = (void *)GetProcAddress( hntdll,
                                                                  "RtlLookupFunctionEntry" );
+    p__C_specific_handler              = (void *)GetProcAddress( hntdll,
+                                                                 "__C_specific_handler" );
 
     test_debug_registers();
     test_outputdebugstring(1, FALSE);
@@ -2275,6 +2357,7 @@ START_TEST(exception)
     test_breakpoint(1);
     test_vectored_continue_handler();
     test_virtual_unwind();
+    test___C_specific_handler();
 
     if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry)
       test_dynamic_unwind();




More information about the wine-cvs mailing list