From 87e5ec8869648028140145acc58be4cf5b07d5f2 Mon Sep 17 00:00:00 2001 From: Daniel Lehman Date: Fri, 19 May 2017 11:03:28 -0700 Subject: [PATCH 2/7] msvcrt: Clean up registered C++ object in handler. this ties into the following commit 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 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 | 64 +++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/dlls/msvcrt/except_x86_64.c b/dlls/msvcrt/except_x86_64.c index 6b0557a..ec18746 100644 --- a/dlls/msvcrt/except_x86_64.c +++ b/dlls/msvcrt/except_x86_64.c @@ -320,33 +320,67 @@ 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 DWORD cxx_catch_cleanup(EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **pdispatcher) +{ + if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) + { + thread_data_t *data = msvcrt_get_thread_data(); + frame_info *cur; + + if (cxx_is_consolidate(rec)) + { + rec = (void*)rec->ExceptionInformation[4]; + + for (cur = data->frame_info_head; cur; cur = cur->next) + { + if ((ULONG64)cur <= (ULONG64)frame) + { + __CxxUnregisterExceptionObject((cxx_frame_info*)cur, + rec->ExceptionCode == CXX_EXCEPTION && + data->exc_record->ExceptionCode == CXX_EXCEPTION && + rec->ExceptionInformation[1] == data->exc_record->ExceptionInformation[1]); + } + } + } + } + return ExceptionContinueSearch; +} + +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); + EXCEPTION_REGISTRATION_RECORD catch_frame; cxx_frame_info frame_info; void *ret_addr; TRACE("calling handler %p\n", handler); /* FIXME: native does local_unwind here in case of exception rethrow */ + catch_frame.Handler = cxx_catch_cleanup; + __wine_push_frame(&catch_frame); __CxxRegisterExceptionObject(&prev_rec, &frame_info); ret_addr = handler(0, frame); __CxxUnregisterExceptionObject(&frame_info, FALSE); + __wine_pop_frame(&catch_frame); + 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, @@ -528,10 +562,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]; @@ -542,18 +572,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; } -- 1.9.5