Signed-off-by: Daniel Lehman dlehman25@gmail.com
--- this sample runs an infinite loop of 'catch: int' built with vs2019: cl /MD /EHs simple.cpp void test_crash_simple(void) { try { throw 0x42; } catch (int x) { printf("catch: int\n"); } }
ret_addr isn't set - remains zero - and the return address in the catch record is the start of the function (ExceptionInformation[8] = ci.ret_addr + BeginAddress)
call_catch_block4 sees this non-null address and resumes at the start of the function where the exception happened and hits the exception again, leading to a crash
this change only sets the return address if non-zero. the catch record is already zeroed by the memset. call_catch_block4 already defaults to the address returned from the handler and only uses the one from the catch_record if non-null
--- dlls/vcruntime140_1/except_x86_64.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/vcruntime140_1/except_x86_64.c b/dlls/vcruntime140_1/except_x86_64.c index 4cc6897223..e1a39c0662 100644 --- a/dlls/vcruntime140_1/except_x86_64.c +++ b/dlls/vcruntime140_1/except_x86_64.c @@ -603,7 +603,8 @@ static inline void find_catch_block4(EXCEPTION_RECORD *rec, CONTEXT *context, (ULONG_PTR)rva_to_ptr(ci.handler, dispatch->ImageBase); catch_record.ExceptionInformation[6] = (ULONG_PTR)untrans_rec; catch_record.ExceptionInformation[7] = (ULONG_PTR)context; - catch_record.ExceptionInformation[8] = (ULONG_PTR)rva_to_ptr( + if (ci.ret_addr) + catch_record.ExceptionInformation[8] = (ULONG_PTR)rva_to_ptr( ci.ret_addr + dispatch->FunctionEntry->BeginAddress, dispatch->ImageBase); RtlUnwindEx((void*)frame, (void*)dispatch->ControlPc, &catch_record, NULL, &ctx, NULL); }