From: Daniel Lehman Subject: [PATCH 6/7] msvcrt: Support rethrowing SEH exceptions. Message-Id: Date: Wed, 24 May 2017 00:55:16 +0000 From f0a5c5a02bde9be48d7392877c1bc46726f28ced Mon Sep 17 00:00:00 2001 From: Daniel Lehman Date: Fri, 19 May 2017 11:35:02 -0700 Subject: [PATCH 6/7] msvcrt: Support rethrowing SEH exceptions. a rethrow in a catch block for an SEH exception should raise the original SEH exception instead of the translated C++ one used to find the catch block this code change saves the untranslated SEH exception in the consolidation record and re-raises it if available during a rethrow the program below produces the following on Windows: trans_int: c0000005 <- int translator current when called for SEGV while searching for catch block catch: int = 42 <- inside catch block for int, setting float translator, rethrow c0000005 klass::~klass <- unwind catch block for int trans_float: c0000005 <- float translator called on frame b() trans_float: c0000005 <- float translator called on frame a() trans_float: c0000005 <- float translator called on frame main(), found catch block catch: float = 42.0 <- catch for translated exception =============================== // cl /Od /MD /EHa standalone.cpp include include include struct klass { klass(void) {} ~klass() { printf("%s\n", __FUNCTION__); } }; void trans_int(unsigned int u, EXCEPTION_POINTERS* ptrs) { printf("%s: %x\n", __FUNCTION__, u); throw 0x42; } void trans_float(unsigned int u, EXCEPTION_POINTERS* ptrs) { printf("%s: %x\n", __FUNCTION__, u); throw 42.0F; } void b(void) { try { int *p = NULL; *p = 0x42; } catch (int x) { klass k; printf("catch: int = %x\n", x); fflush(stdout); _set_se_translator(trans_float); throw; } } void a(void) { try { b(); } catch (klass c) { } } int main(int argc, char **argv) { _se_translator_function orig = _set_se_translator(trans_int); try { a(); } catch (float f) { printf("catch: float = %.1f\n", f); } if (orig) _set_se_translator(orig); return 0; } Signed-off-by: Daniel Lehman --- dlls/msvcrt/except_x86_64.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/dlls/msvcrt/except_x86_64.c b/dlls/msvcrt/except_x86_64.c index 64cf808..8fbeb85 100644 --- a/dlls/msvcrt/except_x86_64.c +++ b/dlls/msvcrt/except_x86_64.c @@ -113,6 +113,7 @@ typedef struct __seh_frame_info EXCEPTION_REGISTRATION_RECORD frame; ULONG64 dest_frame; ULONG64 orig_frame; + EXCEPTION_RECORD *seh_rec; DISPATCHER_CONTEXT *dispatch; const cxx_function_descr *descr; sigjmp_buf jmp; @@ -338,7 +339,7 @@ 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 && + return rec->ExceptionCode==STATUS_UNWIND_CONSOLIDATE && rec->NumberParameters==7 && rec->ExceptionInformation[0]==(ULONG_PTR)call_catch_block; } @@ -374,6 +375,7 @@ 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]; + EXCEPTION_RECORD *untrans_rec = (void*)rec->ExceptionInformation[6]; 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; @@ -392,8 +394,15 @@ static void* WINAPI call_catch_block(EXCEPTION_RECORD *rec) } __EXCEPT(cxx_rethrow_filter) { - _CxxThrowException((exception *)prev_rec->ExceptionInformation[1], - (const cxx_exception_type *)prev_rec->ExceptionInformation[2]); + if (untrans_rec) + { + __CxxUnregisterExceptionObject(&frame_info, FALSE); + RaiseException(untrans_rec->ExceptionCode, untrans_rec->ExceptionFlags, + untrans_rec->NumberParameters, untrans_rec->ExceptionInformation); + } + else + _CxxThrowException((exception *)prev_rec->ExceptionInformation[1], + (const cxx_exception_type *)prev_rec->ExceptionInformation[2]); } __ENDTRY __wine_pop_frame(&catch_frame); @@ -403,8 +412,8 @@ static void* WINAPI call_catch_block(EXCEPTION_RECORD *rec) return ret_addr; } -static inline void find_catch_block(EXCEPTION_RECORD *rec, ULONG64 frame, - DISPATCHER_CONTEXT *dispatch, +static inline void find_catch_block(EXCEPTION_RECORD *rec, EXCEPTION_RECORD *untrans_rec, + ULONG64 frame, DISPATCHER_CONTEXT *dispatch, const cxx_function_descr *descr, cxx_exception_type *info, ULONG64 orig_frame) { @@ -480,7 +489,7 @@ static inline void find_catch_block(EXCEPTION_RECORD *rec, ULONG64 frame, memset(&catch_record, 0, sizeof(catch_record)); catch_record.ExceptionCode = STATUS_UNWIND_CONSOLIDATE; catch_record.ExceptionFlags = EXCEPTION_NONCONTINUABLE; - catch_record.NumberParameters = 6; + catch_record.NumberParameters = 7; catch_record.ExceptionInformation[0] = (ULONG_PTR)call_catch_block; catch_record.ExceptionInformation[1] = orig_frame; catch_record.ExceptionInformation[2] = (ULONG_PTR)descr; @@ -488,6 +497,7 @@ static inline void find_catch_block(EXCEPTION_RECORD *rec, ULONG64 frame, catch_record.ExceptionInformation[4] = (ULONG_PTR)rec; catch_record.ExceptionInformation[5] = (ULONG_PTR)rva_to_ptr(catchblock->handler, dispatch->ImageBase); + catch_record.ExceptionInformation[6] = (ULONG_PTR)untrans_rec; RtlUnwindEx((void*)frame, (void*)dispatch->ControlPc, &catch_record, NULL, &context, NULL); } } @@ -559,7 +569,7 @@ static DWORD seh_translation_handler(EXCEPTION_RECORD *rec ,struct _EXCEPTION_RE exc_type = (cxx_exception_type *)rec->ExceptionInformation[2]; seh_frame = (seh_frame_info *)frame; - find_catch_block(rec, seh_frame->dest_frame, seh_frame->dispatch, + find_catch_block(rec, seh_frame->seh_rec, seh_frame->dest_frame, seh_frame->dispatch, seh_frame->descr, exc_type, seh_frame->orig_frame); __DestructExceptionObject(rec); @@ -677,6 +687,7 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame, seh_frame.frame.Handler = seh_translation_handler; seh_frame.dest_frame = frame; seh_frame.orig_frame = orig_frame; + seh_frame.seh_rec = rec; seh_frame.dispatch = dispatch; seh_frame.descr = descr; __wine_push_frame(&seh_frame.frame); @@ -689,7 +700,7 @@ static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame, } } - find_catch_block(rec, frame, dispatch, descr, exc_type, orig_frame); + find_catch_block(rec, NULL, frame, dispatch, descr, exc_type, orig_frame); return ExceptionContinueSearch; } -- 1.9.5