Module: wine Branch: master Commit: 7163c78234ecce7e2b5aa531927f573c7d4e5d54 URL: https://source.winehq.org/git/wine.git/?a=commit;h=7163c78234ecce7e2b5aa5319...
Author: Alexandre Julliard julliard@winehq.org Date: Thu Feb 11 14:17:03 2021 +0100
ntdll: Close the debug port on thread exit.
Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/kernel32/tests/debugger.c | 95 ++++++++++++++++++++++++++++++++++++++---- dlls/ntdll/loader.c | 2 + dlls/ntdll/thread.c | 1 - 3 files changed, 90 insertions(+), 8 deletions(-)
diff --git a/dlls/kernel32/tests/debugger.c b/dlls/kernel32/tests/debugger.c index 55bcd62f379..118984eec75 100644 --- a/dlls/kernel32/tests/debugger.c +++ b/dlls/kernel32/tests/debugger.c @@ -1779,12 +1779,49 @@ static char *cmd; static DWORD WINAPI debug_and_exit(void *arg) { STARTUPINFOA si = { sizeof(si) }; + HANDLE debug; + ULONG val = 0; + NTSTATUS status; BOOL ret;
ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, DEBUG_PROCESS, NULL, NULL, &si, &pi); ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError()); + debug = pDbgUiGetThreadDebugObject(); + status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation, + &val, sizeof(val), NULL ); + ok( !status, "NtSetInformationDebugObject failed %x\n", status ); + *(HANDLE *)arg = debug; Sleep(200); + ExitThread(0); +} + +static DWORD WINAPI debug_and_wait(void *arg) +{ + STARTUPINFOA si = { sizeof(si) }; + HANDLE debug = *(HANDLE *)arg; + ULONG val = 0; + NTSTATUS status; + BOOL ret; + + pDbgUiSetThreadDebugObject( debug ); + ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, DEBUG_PROCESS, NULL, NULL, &si, &pi); + ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError()); + debug = pDbgUiGetThreadDebugObject(); + status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation, + &val, sizeof(val), NULL ); + ok( !status, "NtSetInformationDebugObject failed %x\n", status ); + Sleep(INFINITE); + ExitThread(0); +} + +static DWORD WINAPI create_debug_port(void *arg) +{ + STARTUPINFOA si = { sizeof(si) }; + NTSTATUS status = pDbgUiConnectToDbg(); + + ok( !status, "DbgUiConnectToDbg failed %x\n", status ); *(HANDLE *)arg = pDbgUiGetThreadDebugObject(); + Sleep( INFINITE ); ExitThread(0); }
@@ -1844,19 +1881,23 @@ static void test_kill_on_exit(const char *argv0) exit_code = run_child_wait( cmd, event ); ok( exit_code == STATUS_DEBUGGER_INACTIVE, "exit code = %08x\n", exit_code);
- /* test that threads don't close the debug port on exit */ + /* test that threads close the debug port on exit */ thread = CreateThread(NULL, 0, debug_and_exit, &debug, 0, &tid); WaitForSingleObject( thread, 1000 ); ok( debug != 0, "no debug port\n" ); - SetEvent( event ); - WaitForSingleObject( pi.hProcess, 100 ); - GetExitCodeProcess( pi.hProcess, &exit_code ); - ok( exit_code == STILL_ACTIVE, "exit code = %08x\n", exit_code); val = 0; status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation, &val, sizeof(val), NULL ); - ok( !status, "NtSetInformationDebugObject failed %x\n", status ); - CloseHandle( debug ); + ok( status == STATUS_INVALID_HANDLE || broken(status == STATUS_SUCCESS), /* wow64 */ + "NtSetInformationDebugObject failed %x\n", status ); + SetEvent( event ); + if (!status) + { + WaitForSingleObject( pi.hProcess, 100 ); + GetExitCodeProcess( pi.hProcess, &exit_code ); + ok( exit_code == STILL_ACTIVE, "exit code = %08x\n", exit_code); + CloseHandle( debug ); + } WaitForSingleObject( pi.hProcess, 1000 ); GetExitCodeProcess( pi.hProcess, &exit_code ); ok( exit_code == 0, "exit code = %08x\n", exit_code); @@ -1864,6 +1905,46 @@ static void test_kill_on_exit(const char *argv0) CloseHandle( pi.hThread ); CloseHandle( thread );
+ /* but not on forced exit */ + status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, DEBUG_KILL_ON_CLOSE ); + ok( !status, "NtCreateDebugObject failed %x\n", status ); + thread = CreateThread(NULL, 0, debug_and_wait, &debug, 0, &tid); + Sleep( 100 ); + ok( debug != 0, "no debug port\n" ); + val = 1; + status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation, + &val, sizeof(val), NULL ); + ok( status == STATUS_SUCCESS, "NtSetInformationDebugObject failed %x\n", status ); + TerminateThread( thread, 0 ); + status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation, + &val, sizeof(val), NULL ); + ok( status == STATUS_SUCCESS, "NtSetInformationDebugObject failed %x\n", status ); + WaitForSingleObject( pi.hProcess, 300 ); + GetExitCodeProcess( pi.hProcess, &exit_code ); + todo_wine + ok( exit_code == STATUS_DEBUGGER_INACTIVE || broken(exit_code == STILL_ACTIVE), /* wow64 */ + "exit code = %08x\n", exit_code); + CloseHandle( pi.hProcess ); + CloseHandle( pi.hThread ); + CloseHandle( thread ); + CloseHandle( debug ); + + debug = 0; + thread = CreateThread(NULL, 0, create_debug_port, &debug, 0, &tid); + Sleep(100); + ok( debug != 0, "no debug port\n" ); + val = 0; + status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation, + &val, sizeof(val), NULL ); + ok( status == STATUS_SUCCESS, "NtSetInformationDebugObject failed %x\n", status ); + TerminateThread( thread, 0 ); + status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation, + &val, sizeof(val), NULL ); + ok( status == STATUS_SUCCESS, "NtSetInformationDebugObject failed %x\n", status ); + CloseHandle( debug ); + CloseHandle( thread ); + + CloseHandle( event ); heap_free(cmd); }
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 378b812868c..84cb7a04ba0 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -3278,6 +3278,8 @@ void WINAPI LdrShutdownThread(void) RtlReleasePebLock();
RtlLeaveCriticalSection( &loader_section ); + if (DbgUiGetThreadDebugObject()) NtClose( DbgUiGetThreadDebugObject() ); + RtlFreeThreadActivationContextStack(); }
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 8e5a3a3a3a3..425e8770294 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -85,7 +85,6 @@ void WINAPI RtlExitUserThread( ULONG status ) NtQueryInformationThread( GetCurrentThread(), ThreadAmILastThread, &last, sizeof(last), NULL ); if (last) RtlExitUserProcess( status ); LdrShutdownThread(); - RtlFreeThreadActivationContextStack(); for (;;) NtTerminateThread( GetCurrentThread(), status ); }