From: Paul Gofman <pgofman@codeweavers.com> --- dlls/ntdll/tests/unwind.c | 54 +++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unwind.c | 39 +++++++++++++++++++++------- 2 files changed, 84 insertions(+), 9 deletions(-) diff --git a/dlls/ntdll/tests/unwind.c b/dlls/ntdll/tests/unwind.c index 77d3d1043b9..55a8d353336 100644 --- a/dlls/ntdll/tests/unwind.c +++ b/dlls/ntdll/tests/unwind.c @@ -1649,6 +1649,60 @@ static void call_virtual_unwind_arm64( void *code_mem, int testnum, const struct if (pRtlVirtualUnwind2) { + if (test->unwind_info) + { + /* EXCEPTION_ACCESS_VIOLATION is thrown on Windows with NULL handler_data if there is no runtime function. */ + new_context = context; + frame = 0xdeadbeef; + status = pRtlVirtualUnwind2( UNW_FLAG_NHANDLER, (ULONG_PTR)code_mem, orig_pc, + (RUNTIME_FUNCTION *)&runtime_func, + (CONTEXT *)&new_context, NULL, NULL, + &frame, &ctx_ptr, NULL, NULL, NULL, 0 ); + ok( status == STATUS_ACCESS_VIOLATION, "got %#lx\n", status ); + ok( frame == (test->results[i].frame_offset ? (ULONG64)fake_stack : 0) + test->results[i].frame, "wrong frame %p/%p\n", + (void *)frame, (char *)(test->results[i].frame_offset ? fake_stack : NULL) + test->results[i].frame ); + + new_context = context; + handler = (void *)0xdeadbeef; + frame = 0xdeadbeef; + status = pRtlVirtualUnwind2( UNW_FLAG_NHANDLER, (ULONG_PTR)code_mem, orig_pc, + (RUNTIME_FUNCTION *)&runtime_func, + (CONTEXT *)&new_context, NULL, NULL, + &frame, &ctx_ptr, NULL, NULL, &handler, 0 ); + ok( status == STATUS_ACCESS_VIOLATION, "got %#lx\n", status ); + ok( frame == (test->results[i].frame_offset ? (ULONG64)fake_stack : 0) + test->results[i].frame, "wrong frame %p/%p\n", + (void *)frame, (char *)(test->results[i].frame_offset ? fake_stack : NULL) + test->results[i].frame ); + if (test->results[i].handler > 0) + ok( (char *)handler == (char *)code_mem + 0x200, "got %p\n", handler ); + else + ok( !handler, "got %p\n", handler ); + } + + new_context = context; + data = (void *)0xdeadbeef; + frame = 0xdeadbeef; + status = pRtlVirtualUnwind2( UNW_FLAG_NHANDLER, (ULONG_PTR)code_mem, orig_pc, + test->unwind_info ? (RUNTIME_FUNCTION *)&runtime_func : NULL, + (CONTEXT *)&new_context, NULL, &data, + &frame, &ctx_ptr, NULL, NULL, NULL, 0 ); + ok( frame == (test->results[i].frame_offset ? (ULONG64)fake_stack : 0) + test->results[i].frame, "wrong frame %p/%p\n", + (void *)frame, (char *)(test->results[i].frame_offset ? fake_stack : NULL) + test->results[i].frame ); + if (runtime_func.Flag && test->results[i].handler > 0) + { + ok( status == STATUS_ACCESS_VIOLATION, "got %#lx.\n", status ); + ok( data == (void *)0xdeadbeef, "got %p.\n", data ); + } + else if (test->results[i].handler < -1) + { + ok( status == STATUS_BAD_FUNCTION_TABLE, "RtlVirtualUnwind2 failed %lx\n", status ); + ok( data == (void *)0xdeadbeef, "handler data set to %p\n", data ); + } + else + { + ok( !status, "got %#lx\n", status ); + ok( data != (void *)0xdeadbeef, "got %p.\n", data ); + } + new_context = context; handler = (void *)0xdeadbeef; data = (void *)0xdeadbeef; diff --git a/dlls/ntdll/unwind.c b/dlls/ntdll/unwind.c index a31940343f1..4dda55e842a 100644 --- a/dlls/ntdll/unwind.c +++ b/dlls/ntdll/unwind.c @@ -794,25 +794,46 @@ NTSTATUS WINAPI RtlVirtualUnwind2( ULONG type, ULONG_PTR base, ULONG_PTR pc, PEXCEPTION_ROUTINE *handler_ret, ULONG flags ) { BOOLEAN final_pc_from_lr = TRUE; + PEXCEPTION_ROUTINE handler; + void *data = NULL; + TRACE( "type %lx base %I64x pc %I64x rva %I64x sp %I64x\n", type, base, pc, pc - base, context->Sp ); if (limit_low || limit_high) FIXME( "limits not supported\n" ); if (!func && pc == context->Lr) return STATUS_BAD_FUNCTION_TABLE; /* invalid leaf function */ - *handler_data = NULL; context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL; if (!func) /* leaf function */ - *handler_ret = NULL; - else if (func->Flag) - *handler_ret = unwind_packed_data( base, pc, func, context, ctx_ptr ); - else - *handler_ret = unwind_full_data( base, pc, func, context, handler_data, ctx_ptr, &final_pc_from_lr ); + { + context->Pc = context->Lr; + *frame_ret = context->Sp; + if (handler_ret) *handler_ret = NULL; + *handler_data = NULL; + return STATUS_SUCCESS; + } - if (final_pc_from_lr) context->Pc = context->Lr; + __TRY + { + if (func->Flag) + handler = unwind_packed_data( base, pc, func, context, ctx_ptr ); + else + handler = unwind_full_data( base, pc, func, context, &data, ctx_ptr, &final_pc_from_lr ); - TRACE( "ret: pc=%I64x lr=%I64x sp=%I64x handler=%p\n", context->Pc, context->Lr, context->Sp, *handler_ret ); - *frame_ret = context->Sp; + if (final_pc_from_lr) context->Pc = context->Lr; + *frame_ret = context->Sp; + + if (handler_ret) *handler_ret = handler; + *handler_data = data; + } + __EXCEPT_PAGE_FAULT + { + WARN( "Access violation.\n" ); + return STATUS_ACCESS_VIOLATION; + } + __ENDTRY + + TRACE( "ret: pc=%I64x lr=%I64x sp=%I64x handler=%p\n", context->Pc, context->Lr, context->Sp, handler ); return STATUS_SUCCESS; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10695