From: Sebastian Lackner sebastian@fds-team.de
Signed-off-by: Alistair Leslie-Hughes leslie_alistair@hotmail.com --- dlls/ntdll/om.c | 26 ++++++++++++++++ dlls/ntdll/tests/exception.c | 71 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 96 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/om.c b/dlls/ntdll/om.c index febe5bd81d..0b56251348 100644 --- a/dlls/ntdll/om.c +++ b/dlls/ntdll/om.c @@ -38,6 +38,7 @@ #include "winternl.h" #include "ntdll_misc.h" #include "wine/server.h" +#include "wine/exception.h"
WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
@@ -377,6 +378,12 @@ NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source, return ret; }
+static LONG WINAPI invalid_handle_exception_handler( EXCEPTION_POINTERS *eptr ) +{ + EXCEPTION_RECORD *rec = eptr->ExceptionRecord; + return (rec->ExceptionCode == EXCEPTION_INVALID_HANDLE) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; +} + /* Everquest 2 / Pirates of the Burning Sea hooks NtClose, so we need a wrapper */ NTSTATUS close_handle( HANDLE handle ) { @@ -390,6 +397,25 @@ NTSTATUS close_handle( HANDLE handle ) } SERVER_END_REQ; if (fd != -1) close( fd ); + + if (ret == STATUS_INVALID_HANDLE && handle && NtCurrentTeb()->Peb->BeingDebugged) + { + __TRY + { + EXCEPTION_RECORD record; + record.ExceptionCode = EXCEPTION_INVALID_HANDLE; + record.ExceptionFlags = 0; + record.ExceptionRecord = NULL; + record.ExceptionAddress = NULL; + record.NumberParameters = 0; + RtlRaiseException( &record ); + } + __EXCEPT(invalid_handle_exception_handler) + { + } + __ENDTRY + } + return ret; }
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index b3592e6e1e..64a23110a5 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -52,6 +52,7 @@ static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE handle, LONG exit_code); static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG); static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL); +static NTSTATUS (WINAPI *pNtClose)(HANDLE);
#if defined(__x86_64__) typedef struct @@ -1091,6 +1092,16 @@ static void test_debugger(void)
if (stage == 10) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } + else if (stage == 11 || stage == 12 || stage == 13) + { + ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_INVALID_HANDLE, + "unexpected exception code %08x, expected %08x\n", de.u.Exception.ExceptionRecord.ExceptionCode, + EXCEPTION_INVALID_HANDLE); + ok(de.u.Exception.ExceptionRecord.NumberParameters == 0, + "unexpected number of parameters %d, expected 0\n", de.u.Exception.ExceptionRecord.NumberParameters); + + if (stage == 12|| stage == 13) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + } else ok(FALSE, "unexpected stage %x\n", stage);
@@ -2895,6 +2906,54 @@ static void test_breakpoint(DWORD numexc) pRtlRemoveVectoredExceptionHandler(vectored_handler); }
+static DWORD invalid_handle_exceptions; + +static LONG CALLBACK invalid_handle_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo) +{ + PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord; + trace("vect. handler %08x addr:%p\n", rec->ExceptionCode, rec->ExceptionAddress); + + ok(rec->ExceptionCode == EXCEPTION_INVALID_HANDLE, "ExceptionCode is %08x instead of %08x\n", + rec->ExceptionCode, EXCEPTION_INVALID_HANDLE); + ok(rec->NumberParameters == 0, "ExceptionParameters is %d instead of 0\n", rec->NumberParameters); + + invalid_handle_exceptions++; + return (rec->ExceptionCode == EXCEPTION_INVALID_HANDLE) ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH; +} + +static void test_closehandle(DWORD numexc, HANDLE handle) +{ + PVOID vectored_handler; + NTSTATUS status; + DWORD res; + + if (!pRtlAddVectoredExceptionHandler || !pRtlRemoveVectoredExceptionHandler || !pRtlRaiseException) + { + skip("RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler or RtlRaiseException not found\n"); + return; + } + + vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, &invalid_handle_vectored_handler); + ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n"); + + invalid_handle_exceptions = 0; + res = CloseHandle(handle); + + ok(!res || (is_wow64 && res), "CloseHandle(%p) unexpectedly succeeded\n", handle); + ok(GetLastError() == ERROR_INVALID_HANDLE, "wrong error code %d instead of %d\n", + GetLastError(), ERROR_INVALID_HANDLE); + ok(invalid_handle_exceptions == numexc, "CloseHandle generated %d exceptions, expected %d\n", + invalid_handle_exceptions, numexc); + + invalid_handle_exceptions = 0; + status = pNtClose(handle); + ok(status == STATUS_INVALID_HANDLE || (is_wow64 && status == 0), "NtClose(%p) returned status %08x\n", handle, status); + ok(invalid_handle_exceptions == numexc, "NtClose generated %d exceptions, expected %d\n", + invalid_handle_exceptions, numexc); + + pRtlRemoveVectoredExceptionHandler(vectored_handler); +} + static void test_vectored_continue_handler(void) { PVOID handler1, handler2; @@ -2949,6 +3008,7 @@ START_TEST(exception) pNtGetContextThread = (void *)GetProcAddress( hntdll, "NtGetContextThread" ); pNtSetContextThread = (void *)GetProcAddress( hntdll, "NtSetContextThread" ); pNtReadVirtualMemory = (void *)GetProcAddress( hntdll, "NtReadVirtualMemory" ); + pNtClose = (void *)GetProcAddress( hntdll, "NtClose" ); pRtlUnwind = (void *)GetProcAddress( hntdll, "RtlUnwind" ); pRtlRaiseException = (void *)GetProcAddress( hntdll, "RtlRaiseException" ); pRtlCaptureContext = (void *)GetProcAddress( hntdll, "RtlCaptureContext" ); @@ -2997,6 +3057,7 @@ START_TEST(exception) if (pRtlRaiseException) { test_stage = 1; + run_rtlraiseexception_test(0x12345); run_rtlraiseexception_test(EXCEPTION_BREAKPOINT); run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE); @@ -3004,6 +3065,7 @@ START_TEST(exception) run_rtlraiseexception_test(0x12345); run_rtlraiseexception_test(EXCEPTION_BREAKPOINT); run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE); + test_stage = 3; test_outputdebugstring(0, FALSE); test_stage = 4; @@ -3020,6 +3082,12 @@ START_TEST(exception) test_breakpoint(0); test_stage = 10; test_breakpoint(1); + test_stage = 11; + test_closehandle(0, (HANDLE)0xdeadbeef); + test_stage = 12; + test_closehandle(1, (HANDLE)0xdeadbeef); + test_stage = 13; + test_closehandle(0, 0); /* Special case. */ } else skip( "RtlRaiseException not found\n" ); @@ -3036,6 +3104,7 @@ START_TEST(exception) test_ripevent(1); test_debug_service(1); test_breakpoint(1); + test_closehandle(0, (HANDLE)0xdeadbeef); test_vectored_continue_handler(); test_debugger(); test_simd_exceptions(); @@ -3043,7 +3112,6 @@ START_TEST(exception) test_dpe_exceptions(); test_prot_fault(); test_thread_context(); - #elif defined(__x86_64__) pRtlAddFunctionTable = (void *)GetProcAddress( hntdll, "RtlAddFunctionTable" ); @@ -3069,6 +3137,7 @@ START_TEST(exception) test_ripevent(1); test_debug_service(1); test_breakpoint(1); + test_closehandle(0, (HANDLE)0xdeadbeef); test_vectored_continue_handler(); test_virtual_unwind(); test___C_specific_handler();