wait_and_close_child_process() simplifies waiting for the child process and closing its handles. And because it uses wait_child_process() this ensures that any error happening in the child process is detected. reload_child_dump() wraps a cryptic WritePrivateProfileStringA() call and avoids having to add a comment every time.
Signed-off-by: Francois Gouget fgouget@codeweavers.com --- dlls/kernel32/tests/process.c | 279 +++++++++++----------------------- 1 file changed, 92 insertions(+), 187 deletions(-)
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index 0f0889073b0..9a2b05914a6 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -203,6 +203,21 @@ static WCHAR* decodeW(const char* str) return ptr; }
+static void wait_and_close_child_process(PROCESS_INFORMATION *pi) +{ + wait_child_process(pi->hProcess); + CloseHandle(pi->hThread); + CloseHandle(pi->hProcess); +} + +static void reload_child_info(const char* resfile) +{ + /* This forces the profile functions to reload the resource file + * after the child process has modified it. + */ + WritePrivateProfileStringA(NULL, NULL, NULL, resfile); +} + /****************************************************************** * init * @@ -615,13 +630,9 @@ static void test_Startup(void) get_file_name(resfile); sprintf(buffer, ""%s" process dump "%s"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info);
+ reload_child_info(resfile); GetStartupInfoA(&si); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", si.lpDesktop); @@ -655,13 +666,9 @@ static void test_Startup(void) get_file_name(resfile); sprintf(buffer, ""%s" process dump "%s"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info);
+ reload_child_info(resfile); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop); okChildString("StartupInfoA", "lpTitle", startup.lpTitle); @@ -695,13 +702,9 @@ static void test_Startup(void) get_file_name(resfile); sprintf(buffer, ""%s" process dump "%s"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info);
+ reload_child_info(resfile); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", si.lpDesktop); okChildString("StartupInfoA", "lpTitle", startup.lpTitle); @@ -735,13 +738,9 @@ static void test_Startup(void) get_file_name(resfile); sprintf(buffer, ""%s" process dump "%s"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info);
+ reload_child_info(resfile); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop); okChildString("StartupInfoA", "lpTitle", startup.lpTitle); @@ -775,13 +774,9 @@ static void test_Startup(void) get_file_name(resfile); sprintf(buffer, ""%s" process dump "%s"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info);
+ reload_child_info(resfile); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop); result = getChildString( "StartupInfoA", "lpTitle" ); @@ -817,13 +812,9 @@ static void test_Startup(void) get_file_name(resfile); sprintf(buffer, ""%s" process dump "%s"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info);
+ reload_child_info(resfile); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop); okChildString("StartupInfoA", "lpTitle", startup.lpTitle); @@ -857,13 +848,9 @@ static void test_Startup(void) get_file_name(resfile); sprintf(buffer, ""%s" process dump "%s"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info);
+ reload_child_info(resfile); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop); okChildString("StartupInfoA", "lpTitle", startup.lpTitle); @@ -920,13 +907,9 @@ static void test_CommandLine(void) ok(startup.lpTitle == NULL, "lpTitle is not NULL\n"); ok(startup.dwFlags == STARTF_USESHOWWINDOW, "unexpected dwFlags %04x\n", startup.dwFlags); ok(startup.wShowWindow == SW_SHOWNORMAL, "unexpected wShowWindow %d\n", startup.wShowWindow); - /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info);
+ reload_child_info(resfile); okChildInt("Arguments", "argcA", 5); okChildString("Arguments", "argvA4", "C:\Program Files\my nice app.exe"); okChildString("Arguments", "argvA5", NULL); @@ -938,13 +921,9 @@ static void test_CommandLine(void) get_file_name(resfile); sprintf(buffer, ""%s" process dump "%s" "a\"b\\" c\" d", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info);
+ reload_child_info(resfile); okChildInt("Arguments", "argcA", 7); okChildString("Arguments", "argvA4", "a"b\"); okChildString("Arguments", "argvA5", "c""); @@ -963,12 +942,9 @@ static void test_CommandLine(void) SetLastError(0xdeadbeef); ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError()); - /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info); + + reload_child_info(resfile); sprintf(buffer, "./%s", exename); okChildInt("Arguments", "argcA", 5); okChildString("Arguments", "argvA0", buffer); @@ -983,12 +959,9 @@ static void test_CommandLine(void) SetLastError(0xdeadbeef); ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError()); - /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info); + + reload_child_info(resfile); sprintf(buffer, ".\%s", exename); okChildString("Arguments", "argvA0", buffer); release_memory(); @@ -1005,12 +978,9 @@ static void test_CommandLine(void) SetLastError(0xdeadbeef); ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError()); - /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info); + + reload_child_info(resfile); if (p) sprintf(buffer, "..%s/%s", p, exename); else sprintf(buffer, "./%s", exename); okChildString("Arguments", "argvA0", buffer); @@ -1030,12 +1000,9 @@ static void test_CommandLine(void) SetLastError(0xdeadbeef); ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError()); - /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info); + + reload_child_info(resfile); okChildString("Arguments", "argvA0", "dummy"); okChildString("Arguments", "CommandLineA", buffer2); okChildStringWA("Arguments", "CommandLineW", buffer2); @@ -1128,13 +1095,9 @@ static void test_Directory(void) sprintf(buffer, ""%s" process dump "%s"", selfname, resfile); GetWindowsDirectoryA( windir, sizeof(windir) ); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, windir, &startup, &info), "CreateProcess\n"); - /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info);
+ reload_child_info(resfile); okChildIString("Misc", "CurrDirA", windir); release_memory(); DeleteFileA(resfile); @@ -1174,11 +1137,9 @@ static void test_Toolhelp(void) get_file_name(resfile); sprintf(buffer, ""%s" process dump "%s"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n"); - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - CloseHandle(info.hProcess); - CloseHandle(info.hThread); + wait_and_close_child_process(&info);
- WritePrivateProfileStringA(NULL, NULL, NULL, resfile); + reload_child_info(resfile); okChildInt("Toolhelp", "cntUsage", 0); okChildInt("Toolhelp", "th32DefaultHeapID", 0); okChildInt("Toolhelp", "th32ModuleID", 0); @@ -1192,7 +1153,7 @@ static void test_Toolhelp(void) get_file_name(resfile); sprintf(buffer, ""%s" process nested "%s"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n"); - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); + wait_child_process(info.hProcess);
process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId); ok(process != NULL, "OpenProcess failed %u\n", GetLastError()); @@ -1214,7 +1175,7 @@ static void test_Toolhelp(void) ok(i < 20 || broken(i == 20), "process object not released\n");
/* Look for the nested process by pid */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); + reload_child_info(resfile); nested_pid = GetPrivateProfileIntA("Nested", "Pid", 0, resfile); DeleteFileA(resfile);
@@ -1253,11 +1214,10 @@ static void test_Toolhelp(void) ok(ret == 1, "expected 1, got %u\n", ret); CloseHandle(thread);
- ret = WaitForSingleObject(process, 30000); - ok(ret == WAIT_OBJECT_0, "Child process termination got %u le=%u\n", ret, GetLastError()); + wait_child_process(process); CloseHandle(process);
- WritePrivateProfileStringA(NULL, NULL, NULL, resfile); + reload_child_info(resfile); okChildInt("Toolhelp", "cntUsage", 0); okChildInt("Toolhelp", "th32DefaultHeapID", 0); okChildInt("Toolhelp", "th32ModuleID", 0); @@ -1353,11 +1313,9 @@ static void test_Environment(void) get_file_name(resfile); sprintf(buffer, ""%s" process dump "%s"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); + wait_and_close_child_process(&info);
+ reload_child_info(resfile); env = GetEnvironmentStringsA(); cmpEnvironment(env); release_memory(); @@ -1410,11 +1368,9 @@ static void test_Environment(void) } *ptr = '\0'; ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, child_env, NULL, &startup, &info), "CreateProcess\n"); - /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); + wait_and_close_child_process(&info);
+ reload_child_info(resfile); cmpEnvironment(child_env);
HeapFree(GetProcessHeap(), 0, child_env); @@ -1446,13 +1402,11 @@ static void test_SuspendFlag(void) ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n"); ok(ResumeThread(info.hThread) == 1, "Resuming thread\n");
- /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); + wait_and_close_child_process(&info);
GetStartupInfoA(&us);
+ reload_child_info(resfile); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", us.lpDesktop); result = getChildString( "StartupInfoA", "lpTitle" ); @@ -1508,13 +1462,11 @@ static void test_DebuggingFlag(void) } while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
ok(dbg, "I have seen a debug event\n"); - /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); + wait_and_close_child_process(&info);
GetStartupInfoA(&us);
+ reload_child_info(resfile); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", us.lpDesktop); result = getChildString( "StartupInfoA", "lpTitle" ); @@ -1588,12 +1540,9 @@ static void test_Console(void) get_file_name(resfile); sprintf(buffer, ""%s" process dump "%s" console", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n"); + wait_and_close_child_process(&info);
- /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); - + reload_child_info(resfile); /* now get the modification the child has made, and resets parents expected values */ ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbiC), "Getting sb info\n"); ok(GetConsoleMode(startup.hStdInput, &modeInC), "Getting console in mode\n"); @@ -1715,11 +1664,9 @@ static void test_Console(void) /* the child may also send the final "n tests executed" string, so read it to avoid a deadlock */ ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL);
- /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); + wait_and_close_child_process(&info);
+ reload_child_info(resfile); okChildString("StdHandle", "msg", msg);
release_memory(); @@ -1743,11 +1690,10 @@ static void test_ExitCode(void) sprintf(buffer, ""%s" process dump "%s" exit_code", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
- /* wait for child to terminate */ + /* not wait_child_process() because of the exit code */ ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - /* child process has changed result file, so let profile functions know about it */ - WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
+ reload_child_info(resfile); ok(GetExitCodeProcess(info.hProcess, &code), "Getting exit code\n"); okChildInt("ExitCode", "value", code);
@@ -2458,7 +2404,6 @@ static void test_IsProcessInJob(void) HANDLE job, job2; PROCESS_INFORMATION pi; BOOL ret, out; - DWORD dwret;
if (!pIsProcessInJob) { @@ -2503,9 +2448,7 @@ static void test_IsProcessInJob(void) ok(out, "IsProcessInJob returned out=%u\n", out);
TerminateProcess(pi.hProcess, 0); - - dwret = WaitForSingleObject(pi.hProcess, 1000); - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); + wait_child_process(pi.hProcess);
out = FALSE; ret = pIsProcessInJob(pi.hProcess, job, &out); @@ -2536,6 +2479,7 @@ static void test_TerminateJobObject(void) ret = pTerminateJobObject(job, 123); ok(ret, "TerminateJobObject error %u\n", GetLastError());
+ /* not wait_child_process() because of the exit code */ dwret = WaitForSingleObject(pi.hProcess, 1000); ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0); @@ -2550,9 +2494,7 @@ static void test_TerminateJobObject(void)
/* Test adding an already terminated process to a job object */ create_process("exit", &pi); - - dwret = WaitForSingleObject(pi.hProcess, 1000); - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); + wait_child_process(pi.hProcess);
SetLastError(0xdeadbeef); ret = pAssignProcessToJobObject(job, pi.hProcess); @@ -2590,9 +2532,7 @@ static void test_QueryInformationJobObject(void) ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
ReleaseSemaphore(sem, 1, NULL); - wait_child_process(pi[0].hProcess); - CloseHandle(pi[0].hProcess); - CloseHandle(pi[0].hThread); + wait_and_close_child_process(&pi[0]);
create_process("wait", &pi[0]); ret = pAssignProcessToJobObject(job, pi[0].hProcess); @@ -2696,7 +2636,6 @@ static void test_CompletionPort(void) JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info; PROCESS_INFORMATION pi; HANDLE job, port; - DWORD dwret; BOOL ret;
job = pCreateJobObjectW(NULL, NULL); @@ -2718,8 +2657,7 @@ static void test_CompletionPort(void) test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
TerminateProcess(pi.hProcess, 0); - dwret = WaitForSingleObject(pi.hProcess, 1000); - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); + wait_child_process(pi.hProcess);
test_completion(port, JOB_OBJECT_MSG_EXIT_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0); test_completion(port, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, (DWORD_PTR)job, 0, 100); @@ -2757,6 +2695,7 @@ static void test_KillOnJobClose(void)
CloseHandle(job);
+ /* not wait_child_process() for the kill */ dwret = WaitForSingleObject(pi.hProcess, 1000); ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0); @@ -2847,9 +2786,7 @@ static void test_WaitForJobObject(void) dwret = WaitForSingleObject(job, 100); ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
- wait_child_process(pi.hProcess); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); + wait_and_close_child_process(&pi); CloseHandle(job); CloseHandle(sem); } @@ -2871,7 +2808,6 @@ static HANDLE test_AddSelfToJob(void) static void test_jobInheritance(HANDLE job) { PROCESS_INFORMATION pi; - DWORD dwret; BOOL ret, out;
if (!pIsProcessInJob) @@ -2887,11 +2823,7 @@ static void test_jobInheritance(HANDLE job) ok(ret, "IsProcessInJob error %u\n", GetLastError()); ok(out, "IsProcessInJob returned out=%u\n", out);
- dwret = WaitForSingleObject(pi.hProcess, 1000); - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); - - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); + wait_and_close_child_process(&pi); }
static void test_BreakawayOk(HANDLE job) @@ -2901,7 +2833,6 @@ static void test_BreakawayOk(HANDLE job) STARTUPINFOA si = {0}; char buffer[MAX_PATH + 23]; BOOL ret, out; - DWORD dwret;
if (!pIsProcessInJob) { @@ -2917,12 +2848,7 @@ static void test_BreakawayOk(HANDLE job) if (ret) { TerminateProcess(pi.hProcess, 0); - - dwret = WaitForSingleObject(pi.hProcess, 1000); - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); - - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); + wait_and_close_child_process(&pi); }
limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK; @@ -2936,11 +2862,7 @@ static void test_BreakawayOk(HANDLE job) ok(ret, "IsProcessInJob error %u\n", GetLastError()); ok(!out, "IsProcessInJob returned out=%u\n", out);
- dwret = WaitForSingleObject(pi.hProcess, 1000); - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); - - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); + wait_and_close_child_process(&pi);
limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info)); @@ -2953,11 +2875,7 @@ static void test_BreakawayOk(HANDLE job) ok(ret, "IsProcessInJob error %u\n", GetLastError()); ok(!out, "IsProcessInJob returned out=%u\n", out);
- dwret = WaitForSingleObject(pi.hProcess, 1000); - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); - - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); + wait_and_close_child_process(&pi);
/* unset breakaway ok */ limit_info.BasicLimitInformation.LimitFlags = 0; @@ -2980,8 +2898,9 @@ static void test_StartupNoConsole(void) sprintf(buffer, ""%s" process dump "%s"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n"); - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); + wait_and_close_child_process(&info); + + reload_child_info(resfile); okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE); okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE); okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE); @@ -3012,9 +2931,9 @@ static void test_DetachConsoleHandles(void) sprintf(buffer, ""%s" process dump "%s"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n"); - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); + wait_and_close_child_process(&info);
+ reload_child_info(resfile); result = GetPrivateProfileIntA("StartupInfoA", "hStdInput", 0, resfile); ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); result = GetPrivateProfileIntA("StartupInfoA", "hStdOutput", 0, resfile); @@ -3204,9 +3123,7 @@ static void test_SuspendProcessNewThread(void) CloseHandle(thread_handle);
TerminateProcess(pi.hProcess, 0); - WaitForSingleObject(pi.hProcess, 10000); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); + wait_and_close_child_process(&pi); }
static void test_SuspendProcessState(void) @@ -3403,9 +3320,7 @@ static void test_SuspendProcessState(void)
CloseHandle(server_pipe_handle); TerminateProcess(pi.hProcess, 0); - WaitForSingleObject(pi.hProcess, 10000); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); + wait_and_close_child_process(&pi); } #else static void test_SuspendProcessNewThread(void) @@ -3452,8 +3367,9 @@ static void test_DetachStdHandles(void) SetStdHandle(STD_ERROR_HANDLE, hstderr);
ok(res, "CreateProcess failed\n"); - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); + wait_and_close_child_process(&info); + + reload_child_info(resfile); okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE); okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE); okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE); @@ -3930,9 +3846,7 @@ void test_parent_process_attribute(unsigned int level, HANDLE read_pipe) ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, (STARTUPINFOA *)&si, &info); ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError()); - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info); #endif si.lpAttributeList = heap_alloc(size); ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size); @@ -3944,9 +3858,7 @@ void test_parent_process_attribute(unsigned int level, HANDLE read_pipe) ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, (STARTUPINFOA *)&si, &info); ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError()); - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info); CloseHandle(handle); pDeleteProcThreadAttributeList(si.lpAttributeList); heap_free(si.lpAttributeList); @@ -3992,11 +3904,7 @@ void test_parent_process_attribute(unsigned int level, HANDLE read_pipe) ok(ret || broken(!ret && GetLastError() == ERROR_INVALID_HANDLE), "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError()); if (ret) - { - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); - } + wait_and_close_child_process(&info); pDeleteProcThreadAttributeList(si.lpAttributeList); heap_free(si.lpAttributeList);
@@ -4027,10 +3935,7 @@ void test_parent_process_attribute(unsigned int level, HANDLE read_pipe) ret = WriteFile(write_pipe, &parent_data, sizeof(parent_data), &size, NULL); }
- /* wait for child to terminate */ - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info);
if (!level) {
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=67926
Your paranoid android.
=== w1064v1507 (64 bit report) ===
kernel32: process:208: unhandled exception 00919230 in child process 0ba4
On Mon, 23 Mar 2020, Marvin wrote: [...]
=== w1064v1507 (64 bit report) ===
kernel32: process:208: unhandled exception 00919230 in child process 0ba4
Ignore this patch: this failure is indeed caused by it. (as per IRC)
To summarize: test_SuspendProcessState() arranges for ExitProcess() to be called by the child process but in the x86_64 case it does not specify the exit code to use (no exit_code field is set on the stack).
So the child process exit code is the result of a race between the parent's TerminateProcess() call (0 exit code) and the child ExitProcess() call (random exit code).
In the 32 bit case the exit code is set to 0 in the child too (remote_rop_chain.exit_code) so there is no issue.
Setting the child process exit code in the 64 bit case is presumably tricky and not the point of the test so the exit code should just be ignored.
I'll resubmit the patch.