From: Daniel Lehman Subject: [PATCH v2 1/2] msvcrt: Clean up registered C++ object in handler. Message-Id: <4d8a7c5c0529467d90db8eb9bc20eb40@RED-INF-MXMB-P4.esri.com> Date: Mon, 5 Jun 2017 22:43:10 +0000 From 2a099a0bf0714d656e49bf41cadb5b0bf73b1f1b Mon Sep 17 00:00:00 2001 From: Daniel Lehman Date: Thu, 1 Jun 2017 10:43:48 -0700 Subject: [PATCH v2 1/2] msvcrt: Clean up registered C++ object in handler. v2: - use __FINALLY_CTX macro - pass C++ object to finally so that it is only cleaned up if not in use this ties into later commits in support of nested c++ exceptions this moves the cleaning up of objects registered in call_catch_block from cxx_frame_handler to a custom handler using __FINALLY_CTX in the 'normal' case, the catch block doesn't rethrow and the registered object is no longer needed. it is removed unconditionally; this behavior is the same as before if the catch block does throw, the cleanup needs to conditionally free the original object. to do this, the new exception record is passed to __FINALLY_CTX in case of a consolidate, the original c++ object is fetched. the new record is compared with the currently registered one to see if it is still in use before this commit: ... call_consolidate call_catch_block <- register c++ obj catch$0 <- cxx_frame_handler, destroy registered objs to this frame ... after this commit: ... call_consolidate call_catch_block <- register c++ obj on entry, cxx_catch_cleanup destroys it on unwind catch$0 ... Signed-off-by: Daniel Lehman --- dlls/msvcrt/except_x86_64.c | 59 ++++++++++++++++++++++++++------------------- dlls/winecrt0/exception.c | 2 +- include/wine/exception.h | 6 ++--- 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/dlls/msvcrt/except_x86_64.c b/dlls/msvcrt/except_x86_64.c index 57fce93..9667489 100644 --- a/dlls/msvcrt/except_x86_64.c +++ b/dlls/msvcrt/except_x86_64.c @@ -318,7 +318,34 @@ static void cxx_local_unwind(ULONG64 frame, DISPATCHER_CONTEXT *dispatch, unwind_help[0] = last_level; } -static inline void* WINAPI call_catch_block(EXCEPTION_RECORD *rec) +static void* WINAPI call_catch_block(EXCEPTION_RECORD *rec); + +static inline BOOL cxx_is_consolidate(const EXCEPTION_RECORD *rec) +{ + return rec->ExceptionCode==STATUS_UNWIND_CONSOLIDATE && rec->NumberParameters==6 && + rec->ExceptionInformation[0]==(ULONG_PTR)call_catch_block; +} + +static void CALLBACK cxx_catch_cleanup(BOOL normal, EXCEPTION_RECORD *rec, void *ctx) +{ + thread_data_t *data = msvcrt_get_thread_data(); + cxx_frame_info *frame = ctx; + + if (normal) + __CxxUnregisterExceptionObject(frame, FALSE); + else + { + if (cxx_is_consolidate(rec)) + rec = (void*)rec->ExceptionInformation[4]; + + __CxxUnregisterExceptionObject(frame, + rec->ExceptionCode == CXX_EXCEPTION && + data->exc_record->ExceptionCode == CXX_EXCEPTION && + rec->ExceptionInformation[1] == data->exc_record->ExceptionInformation[1]); + } +} + +static void* WINAPI call_catch_block(EXCEPTION_RECORD *rec) { ULONG64 frame = rec->ExceptionInformation[1]; const cxx_function_descr *descr = (void*)rec->ExceptionInformation[2]; @@ -332,19 +359,17 @@ static inline void* WINAPI call_catch_block(EXCEPTION_RECORD *rec) /* 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); + __TRY + { + ret_addr = handler(0, frame); + } + __FINALLY_CTX(cxx_catch_cleanup, prev_rec, &frame_info) + unwind_help[0] = -2; unwind_help[1] = -1; return ret_addr; } -static inline BOOL cxx_is_consolidate(const EXCEPTION_RECORD *rec) -{ - return rec->ExceptionCode==STATUS_UNWIND_CONSOLIDATE && rec->NumberParameters==6 && - rec->ExceptionInformation[0]==(ULONG_PTR)call_catch_block; -} - static inline void find_catch_block(EXCEPTION_RECORD *rec, ULONG64 frame, DISPATCHER_CONTEXT *dispatch, const cxx_function_descr *descr, @@ -513,10 +538,6 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame, { 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]; @@ -527,18 +548,6 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame, } 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; } diff --git a/dlls/winecrt0/exception.c b/dlls/winecrt0/exception.c index 0e00f73..b754d07 100644 --- a/dlls/winecrt0/exception.c +++ b/dlls/winecrt0/exception.c @@ -167,7 +167,7 @@ DWORD __wine_finally_ctx_handler( EXCEPTION_RECORD *record, if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) { __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame; - wine_frame->u.finally_func_ctx( FALSE, wine_frame->ctx ); + wine_frame->u.finally_func_ctx( FALSE, record, wine_frame->ctx ); } return ExceptionContinueSearch; } diff --git a/include/wine/exception.h b/include/wine/exception.h index 5bc4d1c..e57af37 100644 --- a/include/wine/exception.h +++ b/include/wine/exception.h @@ -197,10 +197,10 @@ extern DWORD __wine_finally_ctx_handler( EXCEPTION_RECORD *record, } \ } while (0); -#define __FINALLY_CTX(func, context) \ +#define __FINALLY_CTX(func, rec, context) \ } while(0); \ __wine_pop_frame( &__f.frame ); \ - (func)(1, context); \ + (func)(1, rec, context); \ break; \ } else { \ __f.frame.Handler = __wine_finally_ctx_handler; \ @@ -215,7 +215,7 @@ extern DWORD __wine_finally_ctx_handler( EXCEPTION_RECORD *record, typedef LONG (CALLBACK *__WINE_FILTER)(PEXCEPTION_POINTERS); typedef LONG (CALLBACK *__WINE_FILTER_CTX)(PEXCEPTION_POINTERS, void*); typedef void (CALLBACK *__WINE_FINALLY)(BOOL); -typedef void (CALLBACK *__WINE_FINALLY_CTX)(BOOL, void*); +typedef void (CALLBACK *__WINE_FINALLY_CTX)(BOOL, PEXCEPTION_RECORD, void*); #define GetExceptionInformation() (__eptr) #define GetExceptionCode() (__eptr->ExceptionRecord->ExceptionCode) -- 1.9.5