Various new tests for CreateProcess showing a couple of issues in current implementation.
-- v3: kernelbase: Reset std handles gotten by GetStartupInfo(). ntdll,server: Revisit std handles inheritance. kernel32/tests: Add more tests about CreateProcess. kernel32/tests: Introduce a new infrastructure for testing CreateProcess().
From: Eric Pouech epouech@codeweavers.com
Move a couple of existing tests to this infrastructure.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/kernel32/tests/process.c | 394 ++++++++++++++++++++++++---------- 1 file changed, 278 insertions(+), 116 deletions(-)
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index 8bb2748f8e1..028906660ca 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -317,6 +317,37 @@ static void WINAPIV __WINE_PRINTF_ATTR(2,3) childPrintf(HANDLE h, const char* fm WriteFile(h, buffer, strlen(buffer), &w, NULL); }
+/* bits 0..1 contains FILE_TYPE_{UNKNOWN, CHAR, PIPE, DISK} */ +#define HATTR_NULL 0x08 /* NULL handle value */ +#define HATTR_INVALID 0x04 /* INVALID_HANDLE_VALUE */ +#define HATTR_TYPE 0x0c /* valid handle, with type set */ +#define HATTR_INHERIT 0x10 /* inheritance flag set */ + +static unsigned encode_handle_attributes(HANDLE h) +{ + DWORD dw; + unsigned result; + + if (h == NULL) + result = HATTR_NULL; + else if (h == INVALID_HANDLE_VALUE) + result = HATTR_INVALID; + else + { + result = HATTR_TYPE; + dw = GetFileType(h); + if (dw == FILE_TYPE_CHAR || dw == FILE_TYPE_DISK || dw == FILE_TYPE_PIPE) + { + DWORD info; + if (GetHandleInformation(h, &info) && (info & HANDLE_FLAG_INHERIT)) + result |= HATTR_INHERIT; + } + else + dw = FILE_TYPE_UNKNOWN; + result |= dw; + } + return result; +}
/****************************************************************** * doChild @@ -347,17 +378,24 @@ static void doChild(const char* file, const char* option) "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n" "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n" "dwFlags=%lu\nwShowWindow=%u\n" - "hStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n\n", + "hStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n" + "hStdInputEncode=%u\nhStdOutputEncode=%u\nhStdErrorEncode=%u\n\n", siA.cb, encodeA(siA.lpDesktop), encodeA(siA.lpTitle), siA.dwX, siA.dwY, siA.dwXSize, siA.dwYSize, siA.dwXCountChars, siA.dwYCountChars, siA.dwFillAttribute, siA.dwFlags, siA.wShowWindow, - (DWORD_PTR)siA.hStdInput, (DWORD_PTR)siA.hStdOutput, (DWORD_PTR)siA.hStdError); + (DWORD_PTR)siA.hStdInput, (DWORD_PTR)siA.hStdOutput, (DWORD_PTR)siA.hStdError, + encode_handle_attributes(siA.hStdInput), encode_handle_attributes(siA.hStdOutput), + encode_handle_attributes(siA.hStdError));
/* check the console handles in the TEB */ - childPrintf(hFile, "[TEB]\nhStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n\n", + childPrintf(hFile, + "[TEB]\nhStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n" + "hStdInputEncode=%u\nhStdOutputEncode=%u\nhStdErrorEncode=%u\n\n", (DWORD_PTR)params->hStdInput, (DWORD_PTR)params->hStdOutput, - (DWORD_PTR)params->hStdError); + (DWORD_PTR)params->hStdError, + encode_handle_attributes(params->hStdInput), encode_handle_attributes(params->hStdOutput), + encode_handle_attributes(params->hStdError));
/* since GetStartupInfoW is only implemented in win2k, * zero out before calling so we can notice the difference @@ -369,12 +407,15 @@ static void doChild(const char* file, const char* option) "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n" "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n" "dwFlags=%lu\nwShowWindow=%u\n" - "hStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n\n", + "hStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n" + "hStdInputEncode=%u\nhStdOutputEncode=%u\nhStdErrorEncode=%u\n\n", siW.cb, encodeW(siW.lpDesktop), encodeW(siW.lpTitle), siW.dwX, siW.dwY, siW.dwXSize, siW.dwYSize, siW.dwXCountChars, siW.dwYCountChars, siW.dwFillAttribute, siW.dwFlags, siW.wShowWindow, - (DWORD_PTR)siW.hStdInput, (DWORD_PTR)siW.hStdOutput, (DWORD_PTR)siW.hStdError); + (DWORD_PTR)siW.hStdInput, (DWORD_PTR)siW.hStdOutput, (DWORD_PTR)siW.hStdError, + encode_handle_attributes(siW.hStdInput), encode_handle_attributes(siW.hStdOutput), + encode_handle_attributes(siW.hStdError));
/* Arguments */ childPrintf(hFile, "[Arguments]\nargcA=%d\n", myARGC); @@ -595,10 +636,17 @@ static void ok_child_int( int line, const char *sect, const char *key, UINT expe ok_(__FILE__, line)( result == expect, "%s:%s expected %u, but got %u\n", sect, key, expect, result ); }
+static inline void ok_child_hexint( int line, const char *sect, const char *key, UINT expect, UINT is_broken ) +{ + UINT result = GetPrivateProfileIntA( sect, key, !expect, resfile ); + ok_(__FILE__, line)( result == expect || broken( is_broken && result == is_broken ), "%s:%s expected %#x, but got %#x\n", sect, key, expect, result ); +} + #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 ) #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 ) #define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 ) #define okChildInt(sect, key, expect) ok_child_int(__LINE__, (sect), (key), (expect)) +#define okChildHexInt(sect, key, expect, is_broken) ok_child_hexint(__LINE__, (sect), (key), (expect), (is_broken))
static void test_Startup(void) { @@ -3057,72 +3105,241 @@ static void test_BreakawayOk(HANDLE parent_job) ok(ret, "SetInformationJobObject error %lu\n", GetLastError()); }
-static void test_StartupNoConsole(void) +/* copy an executable, but changing its subsystem */ +static inline void copy_change_subsystem(const char* in, const char* out, DWORD subsyst) +{ + BOOL ret; + HANDLE hFile, hMap; + void* mapping; + IMAGE_NT_HEADERS *nthdr; + + ret = CopyFileA(in, out, FALSE); + ok(ret, "Failed to copy executable %s in %s (%lu)\n", in, out, GetLastError()); + + hFile = CreateFileA(out, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + ok(hFile != INVALID_HANDLE_VALUE, "Couldn't open file %s (%lu)\n", out, GetLastError()); + hMap = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, NULL); + ok(hMap != NULL, "Couldn't create map (%lu)\n", GetLastError()); + mapping = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0); + ok(mapping != NULL, "Couldn't map (%lu)\n", GetLastError()); + nthdr = RtlImageNtHeader(mapping); + ok(nthdr != NULL, "Cannot get NT headers out of %s\n", out); + if (nthdr) nthdr->OptionalHeader.Subsystem = subsyst; + ret = UnmapViewOfFile(mapping); + ok(ret, "Couldn't unmap (%lu)\n", GetLastError()); + CloseHandle(hMap); + CloseHandle(hFile); +} + +#define H_CONSOLE 0 +#define H_DISK 1 + +#define ARG_STD 0x80000000 +#define ARG_STARTUPINFO 0x00000000 +#define ARG_CP_INHERIT 0x40000000 +#define ARG_HANDLE_INHERIT 0x20000000 +#define ARG_HANDLE_MASK (~0xff000000) + +static inline BOOL check_run_child(const char *exec, DWORD flags, BOOL cp_inherit, + STARTUPINFOA *si) { -#ifndef _WIN64 - char buffer[2 * MAX_PATH + 25]; - STARTUPINFOA startup; PROCESS_INFORMATION info; + char buffer[2 * MAX_PATH + 64]; + DWORD exit_code; + BOOL res; + DWORD ret;
- memset(&startup, 0, sizeof(startup)); - startup.cb = sizeof(startup); - startup.dwFlags = STARTF_USESHOWWINDOW; - startup.wShowWindow = SW_SHOWNORMAL; get_file_name(resfile); - sprintf(buffer, ""%s" process dump "%s"", selfname, resfile); - ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, - &info), "CreateProcess\n"); - wait_and_close_child_process(&info); + sprintf(buffer, ""%s" process dump "%s"", exec, resfile);
- 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); - okChildInt("TEB", "hStdInput", 0); - okChildInt("TEB", "hStdOutput", 0); - okChildInt("TEB", "hStdError", 0); - release_memory(); - DeleteFileA(resfile); -#endif + res = CreateProcessA(NULL, buffer, NULL, NULL, cp_inherit, flags, NULL, NULL, si, &info); + ok(res, "CreateProcess failed: %lu %s\n", GetLastError(), buffer); + CloseHandle(info.hThread); + ret = WaitForSingleObject(info.hProcess, 30000); + ok(ret == WAIT_OBJECT_0, "Could not wait for the child process: %ld le=%lu\n", + ret, GetLastError()); + res = GetExitCodeProcess(info.hProcess, &exit_code); + ok(res && exit_code == 0, "Couldn't get exit_code\n"); + CloseHandle(info.hProcess); + return res; +} + +static char std_handle_file[MAX_PATH]; + +static inline BOOL build_startupinfo( STARTUPINFOA *startup, unsigned args, HANDLE hstd[2] ) +{ + SECURITY_ATTRIBUTES inherit_sa = { sizeof(inherit_sa), NULL, TRUE }; + SECURITY_ATTRIBUTES *psa; + BOOL needs_close = FALSE; + + psa = (args & ARG_HANDLE_INHERIT) ? &inherit_sa : NULL; + + memset(startup, 0, sizeof(*startup)); + startup->cb = sizeof(*startup); + + switch (args & ARG_HANDLE_MASK) + { + case H_CONSOLE: + hstd[0] = CreateFileA("CONIN$", GENERIC_READ, 0, psa, OPEN_EXISTING, 0, 0); + ok(hstd[0] != INVALID_HANDLE_VALUE, "Couldn't create input to console\n"); + hstd[1] = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, psa, OPEN_EXISTING, 0, 0); + ok(hstd[1] != INVALID_HANDLE_VALUE, "Couldn't create input to console\n"); + needs_close = TRUE; + break; + case H_DISK: + hstd[0] = CreateFileA(std_handle_file, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, psa, OPEN_EXISTING, 0, 0); + ok(hstd[0] != INVALID_HANDLE_VALUE, "Couldn't create input to file %s\n", std_handle_file); + hstd[1] = CreateFileA(std_handle_file, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, psa, OPEN_EXISTING, 0, 0); + ok(hstd[1] != INVALID_HANDLE_VALUE, "Couldn't create input to file %s\n", std_handle_file); + needs_close = TRUE; + break; + default: + ok(0, "Unsupported handle type %x\n", args & ARG_HANDLE_MASK); + return FALSE; + } + + if (args & ARG_STD) + { + SetStdHandle(STD_INPUT_HANDLE, hstd[0]); + SetStdHandle(STD_OUTPUT_HANDLE, hstd[1]); + } + else /* through startup info */ + { + startup->dwFlags |= STARTF_USESTDHANDLES; + startup->hStdInput = hstd[0]; + startup->hStdOutput = hstd[1]; + } + return needs_close; }
-static void test_DetachConsoleHandles(void) +struct std_handle_test +{ + /* input */ + unsigned args; + /* output */ + DWORD expected; + unsigned is_todo; /* bitmask: 1 on TEB values, 2 on StartupInfoA values, 4 on StartupInfoW values */ + DWORD is_broken; /* Win7 broken file types */ +}; + +static void test_StdHandleInheritance(void) { #ifndef _WIN64 - char buffer[2 * MAX_PATH + 25]; - STARTUPINFOA startup; - PROCESS_INFORMATION info; - UINT result; + HANDLE hsavestd[3]; + static char guiexec[MAX_PATH]; + static char cuiexec[MAX_PATH]; + char **argv; + BOOL ret; + int i, j;
- memset(&startup, 0, sizeof(startup)); - startup.cb = sizeof(startup); - startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES; - startup.wShowWindow = SW_SHOWNORMAL; - startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); - startup.hStdError = GetStdHandle(STD_ERROR_HANDLE); - get_file_name(resfile); - sprintf(buffer, ""%s" process dump "%s"", selfname, resfile); - ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, - &info), "CreateProcess\n"); - wait_and_close_child_process(&info); + static const struct std_handle_test + detached_cui[] = + { + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 4}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + /* all others handles type behave as H_DISK */ + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 4}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, + }, + detached_gui[] = + { + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 4}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + /* all others handles type behave as H_DISK */ + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 4}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, + }; + static const struct + { + DWORD cp_flags; + BOOL use_cui; + const struct std_handle_test* tests; + size_t count; + const char* descr; + } + tests[] = + { +#define X(d, cg, s) {(d), (cg), s, ARRAY_SIZE(s), #s} + X(DETACHED_PROCESS, TRUE, detached_cui), + X(DETACHED_PROCESS, FALSE, detached_gui), +#undef X + };
- 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); - ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); - result = GetPrivateProfileIntA("StartupInfoA", "hStdError", 0, resfile); - ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); - result = GetPrivateProfileIntA("TEB", "hStdInput", 0, resfile); - ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); - result = GetPrivateProfileIntA("TEB", "hStdOutput", 0, resfile); - ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); - result = GetPrivateProfileIntA("TEB", "hStdError", 0, resfile); - ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); + hsavestd[0] = GetStdHandle(STD_INPUT_HANDLE); + hsavestd[1] = GetStdHandle(STD_OUTPUT_HANDLE); + hsavestd[2] = GetStdHandle(STD_ERROR_HANDLE);
- release_memory(); - DeleteFileA(resfile); + winetest_get_mainargs(&argv); + + GetTempPathA(ARRAY_SIZE(guiexec), guiexec); + strcat(guiexec, "process_gui.exe"); + copy_change_subsystem(argv[0], guiexec, IMAGE_SUBSYSTEM_WINDOWS_GUI); + GetTempPathA(ARRAY_SIZE(cuiexec), cuiexec); + strcat(cuiexec, "process_cui.exe"); + copy_change_subsystem(argv[0], cuiexec, IMAGE_SUBSYSTEM_WINDOWS_CUI); + get_file_name(std_handle_file); + + for (j = 0; j < ARRAY_SIZE(tests); j++) + { + const struct std_handle_test* std_tests = tests[j].tests; + + for (i = 0; i < tests[j].count; i++) + { + STARTUPINFOA startup; + HANDLE hstd[2] = {}; + BOOL needs_close; + unsigned startup_expected; + + winetest_push_context("%s[%u] ", tests[j].descr, i); + needs_close = build_startupinfo( &startup, std_tests[i].args, hstd ); + + ret = check_run_child(tests[j].use_cui ? cuiexec : guiexec, + tests[j].cp_flags, !!(std_tests[i].args & ARG_CP_INHERIT), + &startup); + ok(ret, "Couldn't run child\n"); + reload_child_info(resfile); + + startup_expected = (std_tests[i].args & ARG_STD) ? HATTR_INVALID : std_tests[i].expected; + + todo_wine_if(std_tests[i].is_todo & 2) + { + okChildHexInt("StartupInfoA", "hStdInputEncode", startup_expected, std_tests[i].is_broken); + okChildHexInt("StartupInfoA", "hStdOutputEncode", startup_expected, std_tests[i].is_broken); + } + + startup_expected = (std_tests[i].args & ARG_STD) ? HATTR_NULL : std_tests[i].expected; + + todo_wine_if(std_tests[i].is_todo & 4) + { + okChildHexInt("StartupInfoW", "hStdInputEncode", startup_expected, std_tests[i].is_broken); + okChildHexInt("StartupInfoW", "hStdOutputEncode", startup_expected, std_tests[i].is_broken); + } + + todo_wine_if(std_tests[i].is_todo & 1) + { + okChildHexInt("TEB", "hStdInputEncode", std_tests[i].expected, std_tests[i].is_broken); + okChildHexInt("TEB", "hStdOutputEncode", std_tests[i].expected, std_tests[i].is_broken); + } + + release_memory(); + DeleteFileA(resfile); + if (needs_close) + { + CloseHandle(hstd[0]); + CloseHandle(hstd[1]); + } + winetest_pop_context(); + } + } + + DeleteFileA(guiexec); + DeleteFileA(cuiexec); + DeleteFileA(std_handle_file); + + SetStdHandle(STD_INPUT_HANDLE, hsavestd[0]); + SetStdHandle(STD_OUTPUT_HANDLE, hsavestd[1]); + SetStdHandle(STD_ERROR_HANDLE, hsavestd[2]); #endif }
@@ -3568,59 +3785,6 @@ static void test_SuspendProcessState(void) } #endif
-static void test_DetachStdHandles(void) -{ -#ifndef _WIN64 - char buffer[2 * MAX_PATH + 25], tempfile[MAX_PATH]; - STARTUPINFOA startup; - PROCESS_INFORMATION info; - HANDLE hstdin, hstdout, hstderr, htemp; - BOOL res; - - hstdin = GetStdHandle(STD_INPUT_HANDLE); - hstdout = GetStdHandle(STD_OUTPUT_HANDLE); - hstderr = GetStdHandle(STD_ERROR_HANDLE); - - get_file_name(tempfile); - htemp = CreateFileA(tempfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); - ok(htemp != INVALID_HANDLE_VALUE, "failed opening temporary file\n"); - - memset(&startup, 0, sizeof(startup)); - startup.cb = sizeof(startup); - startup.dwFlags = STARTF_USESHOWWINDOW; - startup.wShowWindow = SW_SHOWNORMAL; - get_file_name(resfile); - sprintf(buffer, ""%s" process dump "%s"", selfname, resfile); - - SetStdHandle(STD_INPUT_HANDLE, htemp); - SetStdHandle(STD_OUTPUT_HANDLE, htemp); - SetStdHandle(STD_ERROR_HANDLE, htemp); - - res = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, - &info); - - SetStdHandle(STD_INPUT_HANDLE, hstdin); - SetStdHandle(STD_OUTPUT_HANDLE, hstdout); - SetStdHandle(STD_ERROR_HANDLE, hstderr); - - ok(res, "CreateProcess failed\n"); - 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); - okChildInt("TEB", "hStdInput", 0); - okChildInt("TEB", "hStdOutput", 0); - okChildInt("TEB", "hStdError", 0); - release_memory(); - DeleteFileA(resfile); - - CloseHandle(htemp); - DeleteFileA(tempfile); -#endif -} - static void test_GetNumaProcessorNode(void) { SYSTEM_INFO si; @@ -5105,9 +5269,7 @@ START_TEST(process) test_ProcessorCount(); test_RegistryQuota(); test_DuplicateHandle(); - test_StartupNoConsole(); - test_DetachConsoleHandles(); - test_DetachStdHandles(); + test_StdHandleInheritance(); test_GetNumaProcessorNode(); test_session_info(); test_GetLogicalProcessorInformationEx();
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/kernel32/tests/process.c | 44 ++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index 028906660ca..655d2013e31 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -3134,6 +3134,8 @@ static inline void copy_change_subsystem(const char* in, const char* out, DWORD
#define H_CONSOLE 0 #define H_DISK 1 +#define H_CHAR 2 +#define H_PIPE 3
#define ARG_STD 0x80000000 #define ARG_STARTUPINFO 0x00000000 @@ -3171,7 +3173,7 @@ static inline BOOL build_startupinfo( STARTUPINFOA *startup, unsigned args, HAND { SECURITY_ATTRIBUTES inherit_sa = { sizeof(inherit_sa), NULL, TRUE }; SECURITY_ATTRIBUTES *psa; - BOOL needs_close = FALSE; + BOOL ret, needs_close = FALSE;
psa = (args & ARG_HANDLE_INHERIT) ? &inherit_sa : NULL;
@@ -3194,6 +3196,18 @@ static inline BOOL build_startupinfo( STARTUPINFOA *startup, unsigned args, HAND ok(hstd[1] != INVALID_HANDLE_VALUE, "Couldn't create input to file %s\n", std_handle_file); needs_close = TRUE; break; + case H_CHAR: + hstd[0] = CreateFileA("NUL", GENERIC_READ, 0, psa, OPEN_EXISTING, 0, 0); + ok(hstd[0] != INVALID_HANDLE_VALUE, "Couldn't create input to NUL\n"); + hstd[1] = CreateFileA("NUL", GENERIC_READ|GENERIC_WRITE, 0, psa, OPEN_EXISTING, 0, 0); + ok(hstd[1] != INVALID_HANDLE_VALUE, "Couldn't create input to NUL\n"); + needs_close = TRUE; + break; + case H_PIPE: + ret = CreatePipe(&hstd[0], &hstd[1], psa, 0); + ok(ret, "Couldn't create anon pipe\n"); + needs_close = TRUE; + break; default: ok(0, "Unsupported handle type %x\n", args & ARG_HANDLE_MASK); return FALSE; @@ -3234,6 +3248,32 @@ static void test_StdHandleInheritance(void) int i, j;
static const struct std_handle_test + nothing_cui[] = + { + /* all others handles type behave as H_DISK */ +/* 0*/ {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK, .is_todo = 6}, + + /* all others handles type behave as H_DISK */ + {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK, .is_todo = 6}, + }, + nothing_gui[] = + { + /* testing all types because of discrepancies */ +/* 0*/ {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK, .is_todo = 6}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_PIPE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_PIPE}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_PIPE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_PIPE, .is_todo = 6}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CHAR, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR}, +/* 5*/ {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CHAR, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR, .is_todo = 6}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + + /* all others handles type behave as H_DISK */ + {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 7}, + }, detached_cui[] = { {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 4}, @@ -3261,6 +3301,8 @@ static void test_StdHandleInheritance(void) tests[] = { #define X(d, cg, s) {(d), (cg), s, ARRAY_SIZE(s), #s} + X(0, TRUE, nothing_cui), + X(0, FALSE, nothing_gui), X(DETACHED_PROCESS, TRUE, detached_cui), X(DETACHED_PROCESS, FALSE, detached_gui), #undef X
From: Eric Pouech epouech@codeweavers.com
Be more strict on the cases where the std handles are passed to child process.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/kernel32/tests/console.c | 12 ++++++------ dlls/kernel32/tests/process.c | 6 +++--- dlls/ntdll/unix/env.c | 13 +++++++++---- dlls/ntdll/unix/process.c | 2 +- dlls/ntdll/unix/unix_private.h | 3 ++- 5 files changed, 21 insertions(+), 15 deletions(-)
diff --git a/dlls/kernel32/tests/console.c b/dlls/kernel32/tests/console.c index 54d1a80709b..74f8f467a9f 100644 --- a/dlls/kernel32/tests/console.c +++ b/dlls/kernel32/tests/console.c @@ -5014,10 +5014,10 @@ static void test_CreateProcessCUI(void) {FALSE, DETACHED_PROCESS | CREATE_NO_WINDOW, NULL_STD, 0}, /* 5*/ {FALSE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, NULL_STD, 0},
- {FALSE, 0, CONSOLE_STD, 0, TRUE}, + {FALSE, 0, CONSOLE_STD, 0}, {FALSE, DETACHED_PROCESS, CONSOLE_STD, 0}, {FALSE, CREATE_NEW_CONSOLE, CONSOLE_STD, 0}, - {FALSE, CREATE_NO_WINDOW, CONSOLE_STD, 0, TRUE}, + {FALSE, CREATE_NO_WINDOW, CONSOLE_STD, 0}, /*10*/ {FALSE, DETACHED_PROCESS | CREATE_NO_WINDOW, CONSOLE_STD, 0}, {FALSE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, CONSOLE_STD, 0},
@@ -5070,10 +5070,10 @@ static void test_CreateProcessCUI(void) /* 5 */ {TRUE, CREATE_NEW_PROCESS_GROUP, STARTUPINFO_STD, TRUE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER}, {TRUE, 0, STARTUPINFO_STD, FALSE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_ENABLED_CTRLC}, {TRUE, CREATE_NEW_PROCESS_GROUP, STARTUPINFO_STD, FALSE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER}, - {FALSE, 0, CONSOLE_STD, TRUE, 0, .is_todo = TRUE}, - {FALSE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, TRUE, CP_GROUP_LEADER, .is_todo = TRUE}, -/* 10 */ {FALSE, 0, CONSOLE_STD, FALSE, CP_ENABLED_CTRLC, .is_todo = TRUE}, - {FALSE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, FALSE, CP_GROUP_LEADER, .is_todo = TRUE}, + {FALSE, 0, CONSOLE_STD, TRUE, 0}, + {FALSE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, TRUE, CP_GROUP_LEADER}, +/* 10 */ {FALSE, 0, CONSOLE_STD, FALSE, CP_ENABLED_CTRLC}, + {FALSE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, FALSE, CP_GROUP_LEADER}, {FALSE, 0, STARTUPINFO_STD, TRUE, 0, .is_todo = TRUE}, {FALSE, CREATE_NEW_PROCESS_GROUP, STARTUPINFO_STD, TRUE, CP_GROUP_LEADER, .is_todo = TRUE}, {FALSE, 0, STARTUPINFO_STD, FALSE, CP_ENABLED_CTRLC, .is_todo = TRUE}, diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index 655d2013e31..ebe9f890737 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -3255,7 +3255,7 @@ static void test_StdHandleInheritance(void) {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK, .is_todo = 6},
/* all others handles type behave as H_DISK */ - {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 6, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK, .is_todo = 6}, }, nothing_gui[] = @@ -3271,8 +3271,8 @@ static void test_StdHandleInheritance(void) {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN},
/* all others handles type behave as H_DISK */ - {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, - {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 7}, + {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 6, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 4}, }, detached_cui[] = { diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c index 4fd3254b2d2..3cb86da8401 100644 --- a/dlls/ntdll/unix/env.c +++ b/dlls/ntdll/unix/env.c @@ -2146,7 +2146,8 @@ void init_startup_info(void) /*********************************************************************** * create_startup_info */ -void *create_startup_info( const UNICODE_STRING *nt_image, const RTL_USER_PROCESS_PARAMETERS *params, +void *create_startup_info( const UNICODE_STRING *nt_image, ULONG process_flags, + const RTL_USER_PROCESS_PARAMETERS *params, const pe_image_info_t *pe_info, DWORD *info_size ) { startup_info_t *info; @@ -2175,9 +2176,13 @@ void *create_startup_info( const UNICODE_STRING *nt_image, const RTL_USER_PROCES info->console_flags = params->ConsoleFlags; if (pe_info->subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI) info->console = wine_server_obj_handle( params->ConsoleHandle ); - info->hstdin = wine_server_obj_handle( params->hStdInput ); - info->hstdout = wine_server_obj_handle( params->hStdOutput ); - info->hstderr = wine_server_obj_handle( params->hStdError ); + if ((process_flags & PROCESS_CREATE_FLAGS_INHERIT_HANDLES) || + (pe_info->subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI && !(params->dwFlags & STARTF_USESTDHANDLES))) + { + info->hstdin = wine_server_obj_handle( params->hStdInput ); + info->hstdout = wine_server_obj_handle( params->hStdOutput ); + info->hstderr = wine_server_obj_handle( params->hStdError ); + } info->x = params->dwX; info->y = params->dwY; info->xsize = params->dwXSize; diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c index db0d92a1b36..71eab55920d 100644 --- a/dlls/ntdll/unix/process.c +++ b/dlls/ntdll/unix/process.c @@ -802,7 +802,7 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_ goto done; } if (!machine) machine = pe_info.machine; - if (!(startup_info = create_startup_info( attr.ObjectName, params, &pe_info, &startup_info_size ))) + if (!(startup_info = create_startup_info( attr.ObjectName, process_flags, params, &pe_info, &startup_info_size ))) goto done; env_size = get_env_size( params, &winedebug );
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 9aeacc7b823..1362c3a04d8 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -178,7 +178,8 @@ extern struct ldt_copy __wine_ldt_copy;
extern void init_environment( int argc, char *argv[], char *envp[] ); extern void init_startup_info(void); -extern void *create_startup_info( const UNICODE_STRING *nt_image, const RTL_USER_PROCESS_PARAMETERS *params, +extern void *create_startup_info( const UNICODE_STRING *nt_image, ULONG process_flags, + const RTL_USER_PROCESS_PARAMETERS *params, const pe_image_info_t *pe_info, DWORD *info_size ); extern char **build_envp( const WCHAR *envW ); extern char *get_alternate_wineloader( WORD machine );
From: Eric Pouech epouech@codeweavers.com
The std handles gotten from GetStartupInfo are only set when process was created with STARTF_USESTDHANDLES flag. And yes, Ansi and Unicode versions reset the std handles to a different value.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/kernel32/kernel_main.c | 16 ++++++++++++---- dlls/kernel32/tests/process.c | 26 +++++++++++++------------- dlls/kernelbase/process.c | 15 ++++++++++++--- 3 files changed, 37 insertions(+), 20 deletions(-)
diff --git a/dlls/kernel32/kernel_main.c b/dlls/kernel32/kernel_main.c index 7b45db73257..da771df1100 100644 --- a/dlls/kernel32/kernel_main.c +++ b/dlls/kernel32/kernel_main.c @@ -108,10 +108,18 @@ static void copy_startup_info(void) startup_infoA.wShowWindow = rupp->wShowWindow; startup_infoA.cbReserved2 = rupp->RuntimeInfo.MaximumLength; startup_infoA.lpReserved2 = rupp->RuntimeInfo.MaximumLength ? (void*)rupp->RuntimeInfo.Buffer : NULL; - startup_infoA.hStdInput = rupp->hStdInput ? rupp->hStdInput : INVALID_HANDLE_VALUE; - startup_infoA.hStdOutput = rupp->hStdOutput ? rupp->hStdOutput : INVALID_HANDLE_VALUE; - startup_infoA.hStdError = rupp->hStdError ? rupp->hStdError : INVALID_HANDLE_VALUE; - + if (rupp->dwFlags & STARTF_USESTDHANDLES) + { + startup_infoA.hStdInput = rupp->hStdInput; + startup_infoA.hStdOutput = rupp->hStdOutput; + startup_infoA.hStdError = rupp->hStdError; + } + else + { + startup_infoA.hStdInput = INVALID_HANDLE_VALUE; + startup_infoA.hStdOutput = INVALID_HANDLE_VALUE; + startup_infoA.hStdError = INVALID_HANDLE_VALUE; + } RtlReleasePebLock(); }
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index ebe9f890737..6912ab8aef4 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -3252,42 +3252,42 @@ static void test_StdHandleInheritance(void) { /* all others handles type behave as H_DISK */ /* 0*/ {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, - {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK, .is_todo = 6}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK},
/* all others handles type behave as H_DISK */ - {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 6, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, - {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK, .is_todo = 6}, + {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, }, nothing_gui[] = { /* testing all types because of discrepancies */ /* 0*/ {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, - {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK, .is_todo = 6}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_PIPE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_PIPE}, - {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_PIPE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_PIPE, .is_todo = 6}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_PIPE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_PIPE}, {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CHAR, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR}, -/* 5*/ {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CHAR, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR, .is_todo = 6}, +/* 5*/ {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CHAR, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR}, {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, - {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 1, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN},
/* all others handles type behave as H_DISK */ - {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 6, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, - {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 4}, + {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL}, }, detached_cui[] = { - {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 4}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL}, {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, /* all others handles type behave as H_DISK */ - {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 4}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL}, {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, }, detached_gui[] = { - {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 4}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL}, {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, /* all others handles type behave as H_DISK */ - {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 4}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL}, {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, }; static const struct diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 4807e84594d..860af7e7237 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -1280,9 +1280,18 @@ void init_startup_info( RTL_USER_PROCESS_PARAMETERS *params ) startup_infoW.wShowWindow = params->wShowWindow; startup_infoW.cbReserved2 = params->RuntimeInfo.MaximumLength; startup_infoW.lpReserved2 = params->RuntimeInfo.MaximumLength ? (void *)params->RuntimeInfo.Buffer : NULL; - startup_infoW.hStdInput = params->hStdInput ? params->hStdInput : INVALID_HANDLE_VALUE; - startup_infoW.hStdOutput = params->hStdOutput ? params->hStdOutput : INVALID_HANDLE_VALUE; - startup_infoW.hStdError = params->hStdError ? params->hStdError : INVALID_HANDLE_VALUE; + if (params->dwFlags & STARTF_USESTDHANDLES) + { + startup_infoW.hStdInput = params->hStdInput; + startup_infoW.hStdOutput = params->hStdOutput; + startup_infoW.hStdError = params->hStdError; + } + else + { + startup_infoW.hStdInput = NULL; + startup_infoW.hStdOutput = NULL; + startup_infoW.hStdError = NULL; + }
command_lineW = params->CommandLine.Buffer; if (!RtlUnicodeStringToAnsiString( &ansi, ¶ms->CommandLine, TRUE )) command_lineA = ansi.Buffer;
new version pushed; should fix Jacek's comment and win7 testbot failures
Jacek Caban (@jacek) commented about dlls/kernel32/tests/process.c:
}
-static void test_DetachConsoleHandles(void) +struct std_handle_test +{
- /* input */
- unsigned args;
- /* output */
- DWORD expected;
- unsigned is_todo; /* bitmask: 1 on TEB values, 2 on StartupInfoA values, 4 on StartupInfoW values */
- DWORD is_broken; /* Win7 broken file types */
+};
+static void test_StdHandleInheritance(void) { #ifndef _WIN64
This causes warnings on 64-bit clang about unused functions:
``` dlls/kernel32/tests/process.c:639:20: warning: unused function 'ok_child_hexint' [-Wunused-function] 639 | static inline void ok_child_hexint( int line, const char *sect, const char *key, UINT expect, UINT is_broken ) | ^~~~~~~~~~~~~~~ dlls/kernel32/tests/process.c:3109:20: warning: unused function 'copy_change_subsystem' [-Wunused-function] 3109 | static inline void copy_change_subsystem(const char* in, const char* out, DWORD subsyst) | ^~~~~~~~~~~~~~~~~~~~~ dlls/kernel32/tests/process.c:3146:20: warning: unused function 'check_run_child' [-Wunused-function] 3146 | static inline BOOL check_run_child(const char *exec, DWORD flags, BOOL cp_inherit, | ^~~~~~~~~~~~~~~ dlls/kernel32/tests/process.c:3172:20: warning: unused function 'build_startupinfo' [-Wunused-function] 3172 | static inline BOOL build_startupinfo( STARTUPINFOA *startup, unsigned args, HANDLE hstd[2] ) | ^~~~~~~~~~~~~~~~~ ```
I'm not sure why those tests are disabled on 64-bit, a quick test suggests that it should work.
You no longer change server, so please adjust the commit message. It could also be a bit more descriptive, perhaps something like "ntdll: Respect PROCESS_CREATE_FLAGS_INHERIT_HANDLES and STARTF_USESTDHANDLES flags in create_startup_info."
On Thu Nov 30 17:24:54 2023 +0000, Jacek Caban wrote:
This causes warnings on 64-bit clang about unused functions:
dlls/kernel32/tests/process.c:639:20: warning: unused function 'ok_child_hexint' [-Wunused-function] 639 | static inline void ok_child_hexint( int line, const char *sect, const char *key, UINT expect, UINT is_broken ) | ^~~~~~~~~~~~~~~ dlls/kernel32/tests/process.c:3109:20: warning: unused function 'copy_change_subsystem' [-Wunused-function] 3109 | static inline void copy_change_subsystem(const char* in, const char* out, DWORD subsyst) | ^~~~~~~~~~~~~~~~~~~~~ dlls/kernel32/tests/process.c:3146:20: warning: unused function 'check_run_child' [-Wunused-function] 3146 | static inline BOOL check_run_child(const char *exec, DWORD flags, BOOL cp_inherit, | ^~~~~~~~~~~~~~~ dlls/kernel32/tests/process.c:3172:20: warning: unused function 'build_startupinfo' [-Wunused-function] 3172 | static inline BOOL build_startupinfo( STARTUPINFOA *startup, unsigned args, HANDLE hstd[2] ) | ^~~~~~~~~~~~~~~~~
I'm not sure why those tests are disabled on 64-bit, a quick test suggests that it should work.
existing (before this MR) 64bit code doesn't compile well (lots of warning for pointer to integer conversion in 64bit)
that maybe the cause ; don't know for sure
so I wrapped in first commit these function inside a #ifndef block and enabled 64bit compilation after first commit (in separate patch) so that we don't have to first the warnings above and remove all of it afterwards
will do (potentially amending a bit, it's likely your proposal doesn't fit inside the first line limit).