ntdll: Close the debug port on thread exit.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-02-11 14:17:03 +01:00
parent ea33192660
commit 7163c78234
3 changed files with 90 additions and 8 deletions

View File

@ -1779,12 +1779,49 @@ static char *cmd;
static DWORD WINAPI debug_and_exit(void *arg) static DWORD WINAPI debug_and_exit(void *arg)
{ {
STARTUPINFOA si = { sizeof(si) }; STARTUPINFOA si = { sizeof(si) };
HANDLE debug;
ULONG val = 0;
NTSTATUS status;
BOOL ret; BOOL ret;
ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, DEBUG_PROCESS, NULL, NULL, &si, &pi); ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, DEBUG_PROCESS, NULL, NULL, &si, &pi);
ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError()); 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); 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(); *(HANDLE *)arg = pDbgUiGetThreadDebugObject();
Sleep( INFINITE );
ExitThread(0); ExitThread(0);
} }
@ -1844,19 +1881,23 @@ static void test_kill_on_exit(const char *argv0)
exit_code = run_child_wait( cmd, event ); exit_code = run_child_wait( cmd, event );
ok( exit_code == STATUS_DEBUGGER_INACTIVE, "exit code = %08x\n", exit_code); 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); thread = CreateThread(NULL, 0, debug_and_exit, &debug, 0, &tid);
WaitForSingleObject( thread, 1000 ); WaitForSingleObject( thread, 1000 );
ok( debug != 0, "no debug port\n" ); 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; val = 0;
status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation, status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
&val, sizeof(val), NULL ); &val, sizeof(val), NULL );
ok( !status, "NtSetInformationDebugObject failed %x\n", status ); 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 ); CloseHandle( debug );
}
WaitForSingleObject( pi.hProcess, 1000 ); WaitForSingleObject( pi.hProcess, 1000 );
GetExitCodeProcess( pi.hProcess, &exit_code ); GetExitCodeProcess( pi.hProcess, &exit_code );
ok( exit_code == 0, "exit code = %08x\n", 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( pi.hThread );
CloseHandle( thread ); 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); heap_free(cmd);
} }

View File

@ -3278,6 +3278,8 @@ void WINAPI LdrShutdownThread(void)
RtlReleasePebLock(); RtlReleasePebLock();
RtlLeaveCriticalSection( &loader_section ); RtlLeaveCriticalSection( &loader_section );
if (DbgUiGetThreadDebugObject()) NtClose( DbgUiGetThreadDebugObject() );
RtlFreeThreadActivationContextStack();
} }

View File

@ -85,7 +85,6 @@ void WINAPI RtlExitUserThread( ULONG status )
NtQueryInformationThread( GetCurrentThread(), ThreadAmILastThread, &last, sizeof(last), NULL ); NtQueryInformationThread( GetCurrentThread(), ThreadAmILastThread, &last, sizeof(last), NULL );
if (last) RtlExitUserProcess( status ); if (last) RtlExitUserProcess( status );
LdrShutdownThread(); LdrShutdownThread();
RtlFreeThreadActivationContextStack();
for (;;) NtTerminateThread( GetCurrentThread(), status ); for (;;) NtTerminateThread( GetCurrentThread(), status );
} }