From 6a81960f7a38be60f82a8740e1ab45a51abcc17f Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Sun, 28 Sep 2014 23:54:50 +0200 Subject: [PATCH] Added patch to fix differences in exception handling behaviour between Wine and Windows. --- debian/changelog | 3 +- patches/Makefile | 17 ++ ...ption-if-invalid-handle-is-passed-to.patch | 184 ++++++++++++++++++ ...gString-should-throw-the-exception-a.patch | 101 ++++++++++ patches/ntdll-Exception/definition | 3 + 5 files changed, 307 insertions(+), 1 deletion(-) create mode 100644 patches/ntdll-Exception/0001-ntdll-Throw-exception-if-invalid-handle-is-passed-to.patch create mode 100644 patches/ntdll-Exception/0002-ntdll-OutputDebugString-should-throw-the-exception-a.patch create mode 100644 patches/ntdll-Exception/definition diff --git a/debian/changelog b/debian/changelog index 1c8fbbb6..ff742b79 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,11 +1,12 @@ wine-compholio (1.7.28) UNRELEASED; urgency=low - * Added several patches for Unity3D Editor * Added missing recommendation for libtxc-dxtn-s2tc0 on Ubuntu. * Added patch to fix issues with over-the-spot input method. * Added patch to fix winemenubuilder desktop icon wine path (when using multiple wine versions). * Added patch to support FIND_FIRST_EX_CASE_SENSITIVE flag in FindFirstFileExW. * Added patch to send WM_PAINT event during dialog creation. * Added patch to fix issues when driver dispatch routine returns different status codes. + * Added several patches for Unity3D Editor. + * Added patch to fix differences between exception handling behaviour in Wine and Windows. -- Sebastian Lackner Sun, 21 Sep 2014 01:44:14 +0200 wine-compholio (1.7.27) unstable; urgency=low diff --git a/patches/Makefile b/patches/Makefile index 312edd6d..b138907e 100644 --- a/patches/Makefile +++ b/patches/Makefile @@ -40,6 +40,7 @@ PATCHLIST := \ loader-Cmdline_Diagnostics.ok \ ntdll-DOS_Attributes.ok \ ntdll-Dynamic_DST.ok \ + ntdll-Exception.ok \ ntdll-FD_Cache.ok \ ntdll-FileDispositionInformation.ok \ ntdll-Fix_Alignment.ok \ @@ -550,6 +551,22 @@ ntdll-Dynamic_DST.ok: echo '+ { "ntdll-Dynamic_DST", "Sebastian Lackner", "Add Dynamic DST exceptions for Israel Standard Time." },'; \ ) > ntdll-Dynamic_DST.ok +# Patchset ntdll-Exception +# | +# | Included patches: +# | * Fix some differences in exception handling behaviour between Wine and Windows. [by Sebastian Lackner] +# | +# | Modified files: +# | * dlls/kernel32/debugger.c, dlls/ntdll/om.c, dlls/ntdll/tests/exception.c +# | +.INTERMEDIATE: ntdll-Exception.ok +ntdll-Exception.ok: + $(call APPLY_FILE,ntdll-Exception/0001-ntdll-Throw-exception-if-invalid-handle-is-passed-to.patch) + $(call APPLY_FILE,ntdll-Exception/0002-ntdll-OutputDebugString-should-throw-the-exception-a.patch) + @( \ + echo '+ { "ntdll-Exception", "Sebastian Lackner", "Fix some differences in exception handling behaviour between Wine and Windows." },'; \ + ) > ntdll-Exception.ok + # Patchset ntdll-FD_Cache # | # | Included patches: diff --git a/patches/ntdll-Exception/0001-ntdll-Throw-exception-if-invalid-handle-is-passed-to.patch b/patches/ntdll-Exception/0001-ntdll-Throw-exception-if-invalid-handle-is-passed-to.patch new file mode 100644 index 00000000..0df6ce9e --- /dev/null +++ b/patches/ntdll-Exception/0001-ntdll-Throw-exception-if-invalid-handle-is-passed-to.patch @@ -0,0 +1,184 @@ +From 05a69d408bc84fa489f297973e3a0ab384dad635 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Sun, 28 Sep 2014 22:42:46 +0200 +Subject: ntdll: Throw exception if invalid handle is passed to NtClose and + debugger enabled. + +--- + dlls/ntdll/om.c | 27 ++++++++++++++++++ + dlls/ntdll/tests/exception.c | 65 ++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 92 insertions(+) + +diff --git a/dlls/ntdll/om.c b/dlls/ntdll/om.c +index 47a2614..bcc6d69 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); + +@@ -343,6 +344,13 @@ 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 ) + { +@@ -356,6 +364,25 @@ NTSTATUS close_handle( HANDLE handle ) + } + SERVER_END_REQ; + if (fd != -1) close( fd ); ++ ++ if (ret == STATUS_INVALID_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 2074f0a..bc36242 100644 +--- a/dlls/ntdll/tests/exception.c ++++ b/dlls/ntdll/tests/exception.c +@@ -51,6 +51,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__) + static BOOLEAN (CDECL *pRtlAddFunctionTable)(RUNTIME_FUNCTION*, DWORD, DWORD64); +@@ -936,6 +937,16 @@ static void test_debugger(void) + /* here we handle exception */ + } + } ++ else if (stage == 7 || stage == 8) ++ { ++ 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 == 8) continuestatus = DBG_EXCEPTION_NOT_HANDLED; ++ } + else + ok(FALSE, "unexpected stage %x\n", stage); + +@@ -1788,6 +1799,53 @@ static void test_ripevent(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) ++{ ++ 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)0xdeadbeef); ++ ok(!res, "CloseHandle(0xdeadbeef) unexpectedly succeeded\n"); ++ ok(GetLastError() == ERROR_INVALID_HANDLE, "wrong error code %d instead of %d", ++ 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)0xdeadbeef); ++ ok(status == STATUS_INVALID_HANDLE, "NtClose(0xdeadbeef) returned status %08x\n", status); ++ ok(invalid_handle_exceptions == numexc, "NtClose generated %d exceptions, expected %d\n", ++ invalid_handle_exceptions, numexc); ++ ++ pRtlRemoveVectoredExceptionHandler(vectored_handler); ++} ++ + START_TEST(exception) + { + HMODULE hntdll = GetModuleHandleA("ntdll.dll"); +@@ -1802,6 +1860,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" ); + pNtTerminateProcess = (void *)GetProcAddress( hntdll, "NtTerminateProcess" ); +@@ -1865,6 +1924,10 @@ START_TEST(exception) + test_ripevent(0); + test_stage = 6; + test_ripevent(1); ++ test_stage = 7; ++ test_closehandle(0); ++ test_stage = 8; ++ test_closehandle(1); + } + else + skip( "RtlRaiseException not found\n" ); +@@ -1878,6 +1941,7 @@ START_TEST(exception) + test_rtlraiseexception(); + test_outputdebugstring(1, FALSE); + test_ripevent(1); ++ test_closehandle(0); + test_debugger(); + test_simd_exceptions(); + test_fpu_exceptions(); +@@ -1896,6 +1960,7 @@ START_TEST(exception) + + test_outputdebugstring(1, FALSE); + test_ripevent(1); ++ test_closehandle(0); + test_virtual_unwind(); + + if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry) +-- +2.1.1 + diff --git a/patches/ntdll-Exception/0002-ntdll-OutputDebugString-should-throw-the-exception-a.patch b/patches/ntdll-Exception/0002-ntdll-OutputDebugString-should-throw-the-exception-a.patch new file mode 100644 index 00000000..48da39e5 --- /dev/null +++ b/patches/ntdll-Exception/0002-ntdll-OutputDebugString-should-throw-the-exception-a.patch @@ -0,0 +1,101 @@ +From fbc7c0a7ec5822215a9da690ea75d8cb3359bc9e Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Sun, 28 Sep 2014 23:39:51 +0200 +Subject: ntdll: OutputDebugString should throw the exception a second time, if + a debugger is attached. + +--- + dlls/kernel32/debugger.c | 17 +++++++++++++++++ + dlls/ntdll/tests/exception.c | 19 +++++++------------ + 2 files changed, 24 insertions(+), 12 deletions(-) + +diff --git a/dlls/kernel32/debugger.c b/dlls/kernel32/debugger.c +index d4d66b2..981661b 100644 +--- a/dlls/kernel32/debugger.c ++++ b/dlls/kernel32/debugger.c +@@ -277,6 +277,23 @@ void WINAPI OutputDebugStringA( LPCSTR str ) + __ENDTRY + if (caught_by_dbg) return; + ++ /* for some unknown reason Windows sends the exception a second time, if a ++ * debugger is attached, and the event wasn't handled in the first attempt */ ++ if (NtCurrentTeb()->Peb->BeingDebugged) ++ { ++ __TRY ++ { ++ ULONG_PTR args[2]; ++ args[0] = strlen(str) + 1; ++ args[1] = (ULONG_PTR)str; ++ RaiseException( DBG_PRINTEXCEPTION_C, 0, 2, args ); ++ } ++ __EXCEPT(debug_exception_handler) ++ { ++ } ++ __ENDTRY ++ } ++ + /* send string to a system-wide monitor */ + if (!mutex_inited) + { +diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c +index bc36242..3f0e6f5 100644 +--- a/dlls/ntdll/tests/exception.c ++++ b/dlls/ntdll/tests/exception.c +@@ -1724,7 +1724,7 @@ static LONG CALLBACK outputdebugstring_vectored_handler(EXCEPTION_POINTERS *Exce + return EXCEPTION_CONTINUE_SEARCH; + } + +-static void test_outputdebugstring(DWORD numexc, BOOL todo) ++static void test_outputdebugstring(DWORD numexc) + { + PVOID vectored_handler; + +@@ -1739,13 +1739,8 @@ static void test_outputdebugstring(DWORD numexc, BOOL todo) + + outputdebugstring_exceptions = 0; + OutputDebugStringA("Hello World"); +- if (todo) +- todo_wine +- ok(outputdebugstring_exceptions == numexc, "OutputDebugStringA generated %d exceptions, expected %d\n", +- outputdebugstring_exceptions, numexc); +- else +- ok(outputdebugstring_exceptions == numexc, "OutputDebugStringA generated %d exceptions, expected %d\n", +- outputdebugstring_exceptions, numexc); ++ ok(outputdebugstring_exceptions == numexc, "OutputDebugStringA generated %d exceptions, expected %d\n", ++ outputdebugstring_exceptions, numexc); + + pRtlRemoveVectoredExceptionHandler(vectored_handler); + } +@@ -1917,9 +1912,9 @@ START_TEST(exception) + run_rtlraiseexception_test(EXCEPTION_BREAKPOINT); + run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE); + test_stage = 3; +- test_outputdebugstring(0, FALSE); ++ test_outputdebugstring(0); + test_stage = 4; +- test_outputdebugstring(2, TRUE); /* is this a Windows bug? */ ++ test_outputdebugstring(2); + test_stage = 5; + test_ripevent(0); + test_stage = 6; +@@ -1939,7 +1934,7 @@ START_TEST(exception) + test_unwind(); + test_exceptions(); + test_rtlraiseexception(); +- test_outputdebugstring(1, FALSE); ++ test_outputdebugstring(1); + test_ripevent(1); + test_closehandle(0); + test_debugger(); +@@ -1958,7 +1953,7 @@ START_TEST(exception) + pRtlLookupFunctionEntry = (void *)GetProcAddress( hntdll, + "RtlLookupFunctionEntry" ); + +- test_outputdebugstring(1, FALSE); ++ test_outputdebugstring(1); + test_ripevent(1); + test_closehandle(0); + test_virtual_unwind(); +-- +2.1.1 + diff --git a/patches/ntdll-Exception/definition b/patches/ntdll-Exception/definition new file mode 100644 index 00000000..d9e8fb14 --- /dev/null +++ b/patches/ntdll-Exception/definition @@ -0,0 +1,3 @@ +Author: Sebastian Lackner +Subject: Fix some differences in exception handling behaviour between Wine and Windows. +Revision: 1