From 04371c65faed0da0e24f23696d4ca8ca7cefa556 Mon Sep 17 00:00:00 2001 From: Daniel Lehman Date: Tue, 13 Jun 2017 14:05:49 -0700 Subject: [PATCH v3 1/3] msvcrt: Clean up registered C++ objects in handler. v3: with changes from Piotr: - simplify cxx_catch_cleanup - compute tryblock end level and use it in cxx_local_unwind instead of using cxx_catch_unwind ctx.rethrow only has the value FALSE the following patches that add rethrow support will change as needed v2: - use __FINALLY_CTX macro Signed-off-by: Daniel Lehman --- dlls/msvcrt/except_x86_64.c | 72 +++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 41 deletions(-) diff --git a/dlls/msvcrt/except_x86_64.c b/dlls/msvcrt/except_x86_64.c index 57fce93..6103005 100644 --- a/dlls/msvcrt/except_x86_64.c +++ b/dlls/msvcrt/except_x86_64.c @@ -110,6 +110,12 @@ typedef struct __cxx_function_descr typedef struct { + cxx_frame_info frame_info; + BOOL rethrow; +} cxx_catch_ctx; + +typedef struct +{ ULONG64 dest_frame; ULONG64 orig_frame; DISPATCHER_CONTEXT *dispatch; @@ -300,7 +306,7 @@ static void cxx_local_unwind(ULONG64 frame, DISPATCHER_CONTEXT *dispatch, } TRACE("current level: %d, last level: %d\n", trylevel, last_level); - while (trylevel != last_level) + while (trylevel > last_level) { if (trylevel<0 || trylevel>=descr->unwind_count) { @@ -315,25 +321,35 @@ static void cxx_local_unwind(ULONG64 frame, DISPATCHER_CONTEXT *dispatch, } trylevel = unwind_table[trylevel].prev; } - unwind_help[0] = last_level; + unwind_help[0] = trylevel; +} + +static void CALLBACK cxx_catch_cleanup(BOOL normal, void *c) +{ + cxx_catch_ctx *ctx = c; + __CxxUnregisterExceptionObject(&ctx->frame_info, ctx->rethrow); } -static inline void* WINAPI call_catch_block(EXCEPTION_RECORD *rec) +static void* WINAPI call_catch_block(EXCEPTION_RECORD *rec) { ULONG64 frame = rec->ExceptionInformation[1]; const cxx_function_descr *descr = (void*)rec->ExceptionInformation[2]; EXCEPTION_RECORD *prev_rec = (void*)rec->ExceptionInformation[4]; void* (__cdecl *handler)(ULONG64 unk, ULONG64 rbp) = (void*)rec->ExceptionInformation[5]; int *unwind_help = rva_to_ptr(descr->unwind_help, frame); - cxx_frame_info frame_info; + cxx_catch_ctx ctx; void *ret_addr; TRACE("calling handler %p\n", handler); - /* FIXME: native does local_unwind here in case of exception rethrow */ - __CxxRegisterExceptionObject(&prev_rec, &frame_info); - ret_addr = handler(0, frame); - __CxxUnregisterExceptionObject(&frame_info, FALSE); + ctx.rethrow = FALSE; + __CxxRegisterExceptionObject(&prev_rec, &ctx.frame_info); + __TRY + { + ret_addr = handler(0, frame); + } + __FINALLY_CTX(cxx_catch_cleanup, &ctx) + unwind_help[0] = -2; unwind_help[1] = -1; return ret_addr; @@ -469,6 +485,7 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame, DWORD throw_func_off; void *throw_func; UINT i, j; + int unwindlevel = -1; if (descr->magicmagic>CXX_FRAME_MAGIC_VC8) { @@ -502,6 +519,7 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame, if (rva_to_ptr(catchblock->handler, dispatch->ImageBase) == throw_func) { TRACE("nested exception detected\n"); + unwindlevel = tryblock->end_level; orig_frame = *(ULONG64*)rva_to_ptr(catchblock->frame, frame); TRACE("setting orig_frame to %lx\n", orig_frame); } @@ -511,39 +529,11 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame, if (rec->ExceptionFlags & (EH_UNWINDING|EH_EXIT_UNWIND)) { - if (cxx_is_consolidate(rec)) - { - EXCEPTION_RECORD *new_rec = (void*)rec->ExceptionInformation[4]; - thread_data_t *data = msvcrt_get_thread_data(); - frame_info *cur; - - if (rec->ExceptionFlags & EH_TARGET_UNWIND) - { - const cxx_function_descr *orig_descr = (void*)rec->ExceptionInformation[2]; - int end_level = rec->ExceptionInformation[3]; - orig_frame = rec->ExceptionInformation[1]; - - cxx_local_unwind(orig_frame, dispatch, orig_descr, end_level); - } - else if(frame == orig_frame) - cxx_local_unwind(frame, dispatch, descr, -1); - - /* FIXME: we should only unregister frames registered by call_catch_block here */ - for (cur = data->frame_info_head; cur; cur = cur->next) - { - if ((ULONG64)cur <= frame) - { - __CxxUnregisterExceptionObject((cxx_frame_info*)cur, - new_rec->ExceptionCode == CXX_EXCEPTION && - data->exc_record->ExceptionCode == CXX_EXCEPTION && - new_rec->ExceptionInformation[1] == data->exc_record->ExceptionInformation[1]); - } - } - return ExceptionContinueSearch; - } - - if (frame == orig_frame) - cxx_local_unwind(frame, dispatch, descr, rec->ExceptionFlags & EH_TARGET_UNWIND ? trylevel : -1); + if (rec->ExceptionFlags & EH_TARGET_UNWIND) + cxx_local_unwind(orig_frame, dispatch, descr, + cxx_is_consolidate(rec) ? rec->ExceptionInformation[3] : trylevel); + else + cxx_local_unwind(orig_frame, dispatch, descr, unwindlevel); return ExceptionContinueSearch; } if (!descr->tryblock_count) return ExceptionContinueSearch; -- 1.9.5