Commit da8b706f authored by Piotr Caban's avatar Piotr Caban Committed by Alexandre Julliard

msvcrt: Don't call unwind handlers when unwinding nested catch blocks.

parent 2fa86fd6
...@@ -334,7 +334,7 @@ static inline void* WINAPI call_catch_block(EXCEPTION_RECORD *rec) ...@@ -334,7 +334,7 @@ static inline void* WINAPI call_catch_block(EXCEPTION_RECORD *rec)
static inline void find_catch_block(EXCEPTION_RECORD *rec, ULONG64 frame, static inline void find_catch_block(EXCEPTION_RECORD *rec, ULONG64 frame,
DISPATCHER_CONTEXT *dispatch, DISPATCHER_CONTEXT *dispatch,
const cxx_function_descr *descr, const cxx_function_descr *descr,
cxx_exception_type *info) cxx_exception_type *info, ULONG64 orig_frame)
{ {
ULONG64 exc_base = (rec->NumberParameters == 4 ? rec->ExceptionInformation[3] : 0); ULONG64 exc_base = (rec->NumberParameters == 4 ? rec->ExceptionInformation[3] : 0);
int trylevel = ip_to_state(rva_to_ptr(descr->ipmap, dispatch->ImageBase), int trylevel = ip_to_state(rva_to_ptr(descr->ipmap, dispatch->ImageBase),
...@@ -343,38 +343,8 @@ static inline void find_catch_block(EXCEPTION_RECORD *rec, ULONG64 frame, ...@@ -343,38 +343,8 @@ static inline void find_catch_block(EXCEPTION_RECORD *rec, ULONG64 frame,
EXCEPTION_RECORD catch_record; EXCEPTION_RECORD catch_record;
CONTEXT context; CONTEXT context;
UINT i, j; UINT i, j;
ULONG64 orig_frame = frame, throw_base;
DWORD throw_func_off;
void *throw_func;
INT *unwind_help; INT *unwind_help;
/* update orig_frame if it's a nested exception */
throw_func_off = RtlLookupFunctionEntry(dispatch->ControlPc, &throw_base, NULL)->BeginAddress;
throw_func = rva_to_ptr(throw_func_off, throw_base);
TRACE("reconstructed handler pointer: %p\n", throw_func);
for (i=descr->tryblock_count; i>0; i--)
{
const tryblock_info *tryblock = rva_to_ptr(descr->tryblock, dispatch->ImageBase);
tryblock = &tryblock[i-1];
if (trylevel>tryblock->end_level && trylevel<=tryblock->catch_level)
{
for (j=0; j<tryblock->catchblock_count; j++)
{
/* TODO: is it possible to have the same handler for multiple catch blocks? */
const catchblock_info *catchblock = rva_to_ptr(tryblock->catchblock, dispatch->ImageBase);
catchblock = &catchblock[j];
if (rva_to_ptr(catchblock->handler, dispatch->ImageBase) == throw_func)
{
TRACE("nested exception detected\n");
orig_frame = *(ULONG64*)rva_to_ptr(catchblock->frame, frame);
TRACE("setting orig_frame to %lx\n", orig_frame);
}
}
}
}
for (i=descr->tryblock_count; i>0; i--) for (i=descr->tryblock_count; i>0; i--)
{ {
in_catch = rva_to_ptr(descr->tryblock, dispatch->ImageBase); in_catch = rva_to_ptr(descr->tryblock, dispatch->ImageBase);
...@@ -457,7 +427,14 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame, ...@@ -457,7 +427,14 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame,
CONTEXT *context, DISPATCHER_CONTEXT *dispatch, CONTEXT *context, DISPATCHER_CONTEXT *dispatch,
const cxx_function_descr *descr) const cxx_function_descr *descr)
{ {
int trylevel = ip_to_state(rva_to_ptr(descr->ipmap, dispatch->ImageBase),
descr->ipmap_count, dispatch->ControlPc-dispatch->ImageBase);
cxx_exception_type *exc_type; cxx_exception_type *exc_type;
ULONG64 orig_frame = frame;
ULONG64 throw_base;
DWORD throw_func_off;
void *throw_func;
UINT i, j;
if (descr->magic<CXX_FRAME_MAGIC_VC6 || descr->magic>CXX_FRAME_MAGIC_VC8) if (descr->magic<CXX_FRAME_MAGIC_VC6 || descr->magic>CXX_FRAME_MAGIC_VC8)
{ {
...@@ -465,6 +442,32 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame, ...@@ -465,6 +442,32 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame,
return ExceptionContinueSearch; return ExceptionContinueSearch;
} }
/* update orig_frame if it's a nested exception */
throw_func_off = RtlLookupFunctionEntry(dispatch->ControlPc, &throw_base, NULL)->BeginAddress;
throw_func = rva_to_ptr(throw_func_off, throw_base);
TRACE("reconstructed handler pointer: %p\n", throw_func);
for (i=descr->tryblock_count; i>0; i--)
{
const tryblock_info *tryblock = rva_to_ptr(descr->tryblock, dispatch->ImageBase);
tryblock = &tryblock[i-1];
if (trylevel>tryblock->end_level && trylevel<=tryblock->catch_level)
{
for (j=0; j<tryblock->catchblock_count; j++)
{
const catchblock_info *catchblock = rva_to_ptr(tryblock->catchblock, dispatch->ImageBase);
catchblock = &catchblock[j];
if (rva_to_ptr(catchblock->handler, dispatch->ImageBase) == throw_func)
{
TRACE("nested exception detected\n");
orig_frame = *(ULONG64*)rva_to_ptr(catchblock->frame, frame);
TRACE("setting orig_frame to %lx\n", orig_frame);
}
}
}
}
if (rec->ExceptionFlags & (EH_UNWINDING|EH_EXIT_UNWIND)) if (rec->ExceptionFlags & (EH_UNWINDING|EH_EXIT_UNWIND))
{ {
if (rec->ExceptionCode==STATUS_UNWIND_CONSOLIDATE && rec->NumberParameters==6 && if (rec->ExceptionCode==STATUS_UNWIND_CONSOLIDATE && rec->NumberParameters==6 &&
...@@ -476,13 +479,13 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame, ...@@ -476,13 +479,13 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame,
if (rec->ExceptionFlags & EH_TARGET_UNWIND) if (rec->ExceptionFlags & EH_TARGET_UNWIND)
{ {
ULONG64 orig_frame = rec->ExceptionInformation[1];
const cxx_function_descr *orig_descr = (void*)rec->ExceptionInformation[2]; const cxx_function_descr *orig_descr = (void*)rec->ExceptionInformation[2];
int end_level = rec->ExceptionInformation[3]; int end_level = rec->ExceptionInformation[3];
orig_frame = rec->ExceptionInformation[1];
cxx_local_unwind(orig_frame, dispatch, orig_descr, end_level); cxx_local_unwind(orig_frame, dispatch, orig_descr, end_level);
} }
else else if(frame == orig_frame)
cxx_local_unwind(frame, dispatch, descr, -1); cxx_local_unwind(frame, dispatch, descr, -1);
/* FIXME: we should only unregister frames registered by call_catch_block here */ /* FIXME: we should only unregister frames registered by call_catch_block here */
...@@ -499,6 +502,7 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame, ...@@ -499,6 +502,7 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame,
return ExceptionContinueSearch; return ExceptionContinueSearch;
} }
if (frame == orig_frame)
cxx_local_unwind(frame, dispatch, descr, -1); cxx_local_unwind(frame, dispatch, descr, -1);
return ExceptionContinueSearch; return ExceptionContinueSearch;
} }
...@@ -545,7 +549,7 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame, ...@@ -545,7 +549,7 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame,
} }
} }
find_catch_block(rec, frame, dispatch, descr, exc_type); find_catch_block(rec, frame, dispatch, descr, exc_type, orig_frame);
return ExceptionContinueSearch; return ExceptionContinueSearch;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment