Alexandre Julliard : ntdll: Close the debug port on thread exit.

Alexandre Julliard julliard at winehq.org
Thu Feb 11 15:37:14 CST 2021


Module: wine
Branch: master
Commit: 7163c78234ecce7e2b5aa531927f573c7d4e5d54
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=7163c78234ecce7e2b5aa531927f573c7d4e5d54

Author: Alexandre Julliard <julliard at 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 at 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 );
 }
 




More information about the wine-cvs mailing list