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

Signed-off-by: Piotr Caban <piotr@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
oldstable
Piotr Caban 2016-08-17 12:48:13 +02:00 committed by Alexandre Julliard
parent 7c060d0061
commit b23de3cd4a
2 changed files with 91 additions and 8 deletions

View File

@ -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;

View File

@ -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();