From c9f63220e0764118eadd8b92f1c3fd616b6eb8c2 Mon Sep 17 00:00:00 2001 From: Daniel Lehman Date: Thu, 20 Apr 2017 06:21:14 -0700 Subject: [PATCH v2] msvcrt: Handle synchronous flag for x64 C++ exceptions v2: - fix longjmp - add helper for consolidate record adapted from except_i386.c the program below demonstrates the difference the flag can make the destructor is called when /EHa is specified while it is not with /EHs (same is true with /EHsc). separate functions are used because try/catch can't be mixed with __try/__except wine async.exe klass::klass klass::~klass wine sync.exe klass::klass build with: cl /Od /EHa standalone.cpp /link /out:async.exe cl /Od /EHs standalone.cpp /link /out:sync.exe standalone.cpp: &include struct klass { klass(void) {printf("%s\n", __FUNCTION__);} ~klass(void) {printf("%s\n", __FUNCTION__);} }; void cxx_frame_that_throws_segv(void) { klass k; try { int *p = NULL; *p = 0x42; } catch (int i) { } } int main(int argc, char **argv) { __try { cxx_frame_that_throws_segv(); } __except(1) { } return 0; } Signed-off-by: Daniel Lehman --- dlls/msvcrt/cppexcept.h | 2 ++ dlls/msvcrt/except_i386.c | 2 -- dlls/msvcrt/except_x86_64.c | 16 ++++++++++++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/dlls/msvcrt/cppexcept.h b/dlls/msvcrt/cppexcept.h index 6ea5818..2091889 100644 --- a/dlls/msvcrt/cppexcept.h +++ b/dlls/msvcrt/cppexcept.h @@ -26,6 +26,8 @@ #define CXX_FRAME_MAGIC_VC8 0x19930522 #define CXX_EXCEPTION 0xe06d7363 +#define FUNC_DESCR_SYNCHRONOUS 1 /* synchronous exceptions only (built with /EHs and /EHsc) */ + typedef void (*vtable_ptr)(void); /* type_info object, see cpp.c for implementation */ diff --git a/dlls/msvcrt/except_i386.c b/dlls/msvcrt/except_i386.c index d26a864..963bd58 100644 --- a/dlls/msvcrt/except_i386.c +++ b/dlls/msvcrt/except_i386.c @@ -96,8 +96,6 @@ typedef struct __cxx_function_descr UINT flags; /* flags when magic >= VC8 */ } cxx_function_descr; -#define FUNC_DESCR_SYNCHRONOUS 1 /* synchronous exceptions only (built with /EHs) */ - typedef struct _SCOPETABLE { int previousTryLevel; diff --git a/dlls/msvcrt/except_x86_64.c b/dlls/msvcrt/except_x86_64.c index d299608..8210f7b 100644 --- a/dlls/msvcrt/except_x86_64.c +++ b/dlls/msvcrt/except_x86_64.c @@ -331,6 +331,12 @@ static inline void* WINAPI call_catch_block(EXCEPTION_RECORD *rec) 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, @@ -442,6 +448,13 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame, return ExceptionContinueSearch; } + if (descr->magic >= CXX_FRAME_MAGIC_VC8 && + (descr->flags & FUNC_DESCR_SYNCHRONOUS) && + (rec->ExceptionCode != CXX_EXCEPTION && + !cxx_is_consolidate(rec) && + rec->ExceptionCode != STATUS_LONGJUMP)) + return ExceptionContinueSearch; /* handle only c++ exceptions */ + /* 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); @@ -470,8 +483,7 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame, if (rec->ExceptionFlags & (EH_UNWINDING|EH_EXIT_UNWIND)) { - if (rec->ExceptionCode==STATUS_UNWIND_CONSOLIDATE && rec->NumberParameters==6 && - rec->ExceptionInformation[0]==(ULONG_PTR)call_catch_block) + if (cxx_is_consolidate(rec)) { EXCEPTION_RECORD *new_rec = (void*)rec->ExceptionInformation[4]; thread_data_t *data = msvcrt_get_thread_data(); -- 1.9.5