1 /* 2 * PROJECT: ReactOS api tests 3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory 4 * PURPOSE: Test for TerminateProcess 5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org> 6 */ 7 8 #include "precomp.h" 9 10 #include <ndk/obfuncs.h> 11 12 static 13 HANDLE 14 StartChild( 15 _In_ PCWSTR Argument, 16 _In_ DWORD Flags, 17 _Out_opt_ PDWORD ProcessId) 18 { 19 BOOL Success; 20 WCHAR FileName[MAX_PATH]; 21 WCHAR CommandLine[MAX_PATH]; 22 STARTUPINFOW StartupInfo; 23 PROCESS_INFORMATION ProcessInfo; 24 25 GetModuleFileNameW(NULL, FileName, _countof(FileName)); 26 StringCbPrintfW(CommandLine, 27 sizeof(CommandLine), 28 L"\"%ls\" TerminateProcess %ls", 29 FileName, 30 Argument); 31 32 RtlZeroMemory(&StartupInfo, sizeof(StartupInfo)); 33 StartupInfo.cb = sizeof(StartupInfo); 34 /* HACK: running the test under rosautotest seems to keep another reference 35 * to the child process around until the test finishes (on both ROS and 36 * Windows)... I'm too lazy to investigate very much so let's just redirect 37 * the child std handles to nowhere. ok() is useless in half the child 38 * processes anyway. 39 */ 40 StartupInfo.dwFlags = STARTF_USESTDHANDLES; 41 42 Success = CreateProcessW(FileName, 43 CommandLine, 44 NULL, 45 NULL, 46 FALSE, 47 Flags, 48 NULL, 49 NULL, 50 &StartupInfo, 51 &ProcessInfo); 52 if (!Success) 53 { 54 skip("CreateProcess failed with %lu\n", GetLastError()); 55 if (ProcessId) 56 *ProcessId = 0; 57 return NULL; 58 } 59 CloseHandle(ProcessInfo.hThread); 60 if (ProcessId) 61 *ProcessId = ProcessInfo.dwProcessId; 62 return ProcessInfo.hProcess; 63 } 64 65 static 66 VOID 67 TraceHandleCount_( 68 _In_ HANDLE hObject, 69 _In_ PCSTR File, 70 _In_ INT Line) 71 { 72 NTSTATUS Status; 73 OBJECT_BASIC_INFORMATION BasicInfo; 74 75 Status = NtQueryObject(hObject, 76 ObjectBasicInformation, 77 &BasicInfo, 78 sizeof(BasicInfo), 79 NULL); 80 if (!NT_SUCCESS(Status)) 81 { 82 ok_(File, Line)(0, "NtQueryObject failed with status 0x%lx\n", Status); 83 return; 84 } 85 ok_(File, Line)(0, "Handle %p still has %lu open handles, %lu references\n", hObject, BasicInfo.HandleCount, BasicInfo.PointerCount); 86 } 87 88 #define WaitExpectSuccess(h, ms) WaitExpect_(h, ms, WAIT_OBJECT_0, __FILE__, __LINE__) 89 #define WaitExpectTimeout(h, ms) WaitExpect_(h, ms, WAIT_TIMEOUT, __FILE__, __LINE__) 90 static 91 VOID 92 WaitExpect_( 93 _In_ HANDLE hWait, 94 _In_ DWORD Milliseconds, 95 _In_ DWORD ExpectedError, 96 _In_ PCSTR File, 97 _In_ INT Line) 98 { 99 DWORD Error; 100 101 Error = WaitForSingleObject(hWait, Milliseconds); 102 ok_(File, Line)(Error == ExpectedError, "Wait for %p return %lu\n", hWait, Error); 103 } 104 105 #define CloseProcessAndVerify(hp, pid, code) CloseProcessAndVerify_(hp, pid, code, __FILE__, __LINE__) 106 static 107 VOID 108 CloseProcessAndVerify_( 109 _In_ HANDLE hProcess, 110 _In_ DWORD ProcessId, 111 _In_ UINT ExpectedExitCode, 112 _In_ PCSTR File, 113 _In_ INT Line) 114 { 115 int i = 0; 116 DWORD Error; 117 DWORD ExitCode; 118 BOOL Success; 119 120 WaitExpect_(hProcess, 0, WAIT_OBJECT_0, File, Line); 121 Success = GetExitCodeProcess(hProcess, &ExitCode); 122 ok_(File, Line)(Success, "GetExitCodeProcess failed with %lu\n", GetLastError()); 123 CloseHandle(hProcess); 124 while ((hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ProcessId)) != NULL) 125 { 126 if (++i >= 100) 127 { 128 TraceHandleCount_(hProcess, File, Line); 129 CloseHandle(hProcess); 130 break; 131 } 132 CloseHandle(hProcess); 133 Sleep(100); 134 } 135 Error = GetLastError(); 136 ok_(File, Line)(hProcess == NULL, "OpenProcess succeeded unexpectedly for pid 0x%lx\n", ProcessId); 137 ok_(File, Line)(Error == ERROR_INVALID_PARAMETER, "Error = %lu\n", Error); 138 ok_(File, Line)(ExitCode == ExpectedExitCode, "Exit code is %lu but expected %u\n", ExitCode, ExpectedExitCode); 139 } 140 141 static 142 VOID 143 TestTerminateProcess( 144 _In_ HANDLE hEvent) 145 { 146 HANDLE hProcess; 147 DWORD ProcessId; 148 149 /* Regular child process that returns from the test function */ 150 /* HACK: These two tests don't work if stdout is a pipe. See StartChild */ 151 ResetEvent(hEvent); 152 hProcess = StartChild(L"child", 0, &ProcessId); 153 WaitExpectSuccess(hEvent, 5000); 154 WaitExpectSuccess(hProcess, 5000); 155 CloseProcessAndVerify(hProcess, ProcessId, 0); 156 157 ResetEvent(hEvent); 158 hProcess = StartChild(L"child", 0, &ProcessId); 159 WaitExpectSuccess(hProcess, 5000); 160 WaitExpectSuccess(hEvent, 0); 161 CloseProcessAndVerify(hProcess, ProcessId, 0); 162 163 /* Suspended process -- never gets a chance to initialize */ 164 ResetEvent(hEvent); 165 hProcess = StartChild(L"child", CREATE_SUSPENDED, &ProcessId); 166 WaitExpectTimeout(hEvent, 100); 167 WaitExpectTimeout(hProcess, 100); 168 TerminateProcess(hProcess, 123); 169 WaitExpectSuccess(hProcess, 5000); 170 CloseProcessAndVerify(hProcess, ProcessId, 123); 171 172 /* Waiting process -- we have to terminate it */ 173 ResetEvent(hEvent); 174 hProcess = StartChild(L"wait", 0, &ProcessId); 175 WaitExpectTimeout(hProcess, 100); 176 TerminateProcess(hProcess, 123); 177 WaitExpectSuccess(hProcess, 5000); 178 CloseProcessAndVerify(hProcess, ProcessId, 123); 179 180 /* Process calls ExitProcess */ 181 ResetEvent(hEvent); 182 hProcess = StartChild(L"child exit 456", 0, &ProcessId); 183 WaitExpectSuccess(hEvent, 5000); 184 WaitExpectSuccess(hProcess, 5000); 185 CloseProcessAndVerify(hProcess, ProcessId, 456); 186 187 /* Process calls TerminateProcess with GetCurrentProcess */ 188 ResetEvent(hEvent); 189 hProcess = StartChild(L"child terminate 456", 0, &ProcessId); 190 WaitExpectSuccess(hEvent, 5000); 191 WaitExpectSuccess(hProcess, 5000); 192 CloseProcessAndVerify(hProcess, ProcessId, 456); 193 194 /* Process calls TerminateProcess with real handle to itself */ 195 ResetEvent(hEvent); 196 hProcess = StartChild(L"child terminate2 456", 0, &ProcessId); 197 WaitExpectSuccess(hEvent, 5000); 198 WaitExpectSuccess(hProcess, 5000); 199 CloseProcessAndVerify(hProcess, ProcessId, 456); 200 } 201 202 START_TEST(TerminateProcess) 203 { 204 HANDLE hEvent; 205 BOOL Success; 206 DWORD Error; 207 int argc; 208 char **argv; 209 210 hEvent = CreateEventW(NULL, TRUE, FALSE, L"kernel32_apitest_TerminateProcess_event"); 211 Error = GetLastError(); 212 if (!hEvent) 213 { 214 skip("CreateEvent failed with error %lu\n", Error); 215 return; 216 } 217 argc = winetest_get_mainargs(&argv); 218 if (argc >= 3) 219 { 220 ok(Error == ERROR_ALREADY_EXISTS, "Error = %lu\n", Error); 221 if (!strcmp(argv[2], "wait")) 222 { 223 WaitExpectSuccess(hEvent, 30000); 224 } 225 else 226 { 227 Success = SetEvent(hEvent); 228 ok(Success, "SetEvent failed with return %d, error %lu\n", Success, GetLastError()); 229 } 230 } 231 else 232 { 233 ok(Error == NO_ERROR, "Error = %lu\n", Error); 234 TestTerminateProcess(hEvent); 235 } 236 CloseHandle(hEvent); 237 if (argc >= 5) 238 { 239 UINT ExitCode = strtol(argv[4], NULL, 10); 240 241 fflush(stdout); 242 if (!strcmp(argv[3], "exit")) 243 ExitProcess(ExitCode); 244 else if (!strcmp(argv[3], "terminate")) 245 TerminateProcess(GetCurrentProcess(), ExitCode); 246 else if (!strcmp(argv[3], "terminate2")) 247 { 248 HANDLE hProcess; 249 hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, GetCurrentProcessId()); 250 TerminateProcess(hProcess, ExitCode); 251 } 252 ok(0, "Should have terminated\n"); 253 } 254 } 255