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