From: Paul Gofman Subject: [PATCH v3 4/4] kernel32/tests: Test std handle inheritance in test_parent_process_attribute(). Message-Id: <20191212111833.672808-4-gofmanp@gmail.com> Date: Thu, 12 Dec 2019 14:18:33 +0300 In-Reply-To: <20191212111833.672808-1-gofmanp@gmail.com> References: <20191212111833.672808-1-gofmanp@gmail.com> Signed-off-by: Paul Gofman --- v2: - added test; v3: - no changes. dlls/kernel32/tests/process.c | 55 ++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index 1194c54202..92838c09ff 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -92,6 +92,7 @@ static SIZE_T (WINAPI *pGetLargePageMinimum)(void); static BOOL (WINAPI *pInitializeProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD, SIZE_T*); static BOOL (WINAPI *pUpdateProcThreadAttribute)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD_PTR, void *,SIZE_T,void*,SIZE_T*); static void (WINAPI *pDeleteProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*); +static DWORD (WINAPI *pGetFinalPathNameByHandleA)(HANDLE, LPSTR, DWORD, DWORD); /* ############################### */ static char base[MAX_PATH]; @@ -259,6 +260,7 @@ static BOOL init(void) pInitializeProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "InitializeProcThreadAttributeList"); pUpdateProcThreadAttribute = (void *)GetProcAddress(hkernel32, "UpdateProcThreadAttribute"); pDeleteProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "DeleteProcThreadAttributeList"); + pGetFinalPathNameByHandleA = (void *)GetProcAddress(hkernel32, "GetFinalPathNameByHandleA"); return TRUE; } @@ -3827,7 +3829,7 @@ static void test_ProcThreadAttributeList(void) * level 2: Process created by level 1 process with handle inheritance and level 0 * process parent substitute. * level 255: Process created by level 1 process during invalid parent handles testing. */ -void test_parent_process_attribute(unsigned int level, HANDLE read_pipe) +void test_parent_process_attribute(unsigned int level, HANDLE read_pipe, HANDLE creator_stdhandle) { PROCESS_BASIC_INFORMATION pbi; char buffer[MAX_PATH + 64]; @@ -3837,7 +3839,9 @@ void test_parent_process_attribute(unsigned int level, HANDLE read_pipe) STARTUPINFOEXA si; DWORD parent_id; NTSTATUS status; + DWORD exit_code; ULONG pbi_size; + HANDLE hstderr; HANDLE parent; DWORD size; BOOL ret; @@ -3885,8 +3889,24 @@ void test_parent_process_attribute(unsigned int level, HANDLE read_pipe) if (level == 2) { + char file_path[MAX_PATH]; + ok(parent_id == parent_data.parent_id, "Got parent id %u, parent_data.parent_id %u.\n", parent_id, parent_data.parent_id); + + GetStartupInfoA(&si.StartupInfo); + hstderr = si.StartupInfo.hStdError; + + /* On Windows, std handle values are copied from creator process but seems not to be inherited from it. + * Some operation on such handle may sometimes succeed, but various way of quering information + * from such handle suggest that the handle refers to some other object. + * Windows seem to just keep the handle value, even for invalid handle. It does not always work exacly + * like that in Wine now due to special handling of console handles in kernelbase/process.c:create_process_params() + * and initialization in dlls/msvcrt: msvcrt_init_io(). */ + ok(hstderr == creator_stdhandle, "Unexpected hstderr %p, creator_hstdhandle %p.\n", + hstderr, creator_stdhandle); + size = pGetFinalPathNameByHandleA(hstderr, file_path, sizeof(file_path), FILE_NAME_NORMALIZED); + ok(!size, "Got unexpected size %u.\n", size); return; } @@ -3902,7 +3922,7 @@ void test_parent_process_attribute(unsigned int level, HANDLE read_pipe) ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError()); - sprintf(buffer, "\"%s\" tests/process.c parent %u %p", selfname, 255, read_pipe); + sprintf(buffer, "\"%s\" tests/process.c parent %u %p %p", selfname, 255, read_pipe, NULL); #if 0 /* Crashes on some Windows installations, otherwise successfully creates process. */ @@ -3988,9 +4008,17 @@ void test_parent_process_attribute(unsigned int level, HANDLE read_pipe) ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parent, sizeof(parent), NULL, NULL); ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError()); + + hstderr = CreateFileA("stderr_1.tmp", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL); + ok(hstderr != INVALID_HANDLE_VALUE, "Could not create file, GetLastError() %u.\n", GetLastError()); + si.StartupInfo.dwFlags = STARTF_USESTDHANDLES; + si.StartupInfo.hStdError = hstderr; + si.StartupInfo.hStdOutput = creator_stdhandle; } - sprintf(buffer, "\"%s\" tests/process.c parent %u %p", selfname, level + 1, read_pipe); + sprintf(buffer, "\"%s\" tests/process.c parent %u %p %p", selfname, level + 1, read_pipe, + level ? hstderr : GetStdHandle(STD_OUTPUT_HANDLE)); ret = CreateProcessA(NULL, buffer, NULL, NULL, level == 1, level == 1 ? EXTENDED_STARTUPINFO_PRESENT : 0, NULL, NULL, (STARTUPINFOA *)&si, &info); ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError()); @@ -4008,10 +4036,16 @@ void test_parent_process_attribute(unsigned int level, HANDLE read_pipe) /* wait for child to terminate */ ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); + GetExitCodeProcess(info.hProcess, &exit_code); + ok(!exit_code, "Child test failed, exit_code %#x.\n", exit_code); + CloseHandle(info.hThread); CloseHandle(info.hProcess); - - if (!level) + if (level) + { + CloseHandle(hstderr); + } + else { CloseHandle(read_pipe); CloseHandle(write_pipe); @@ -4062,12 +4096,13 @@ START_TEST(process) CloseHandle(info.hThread); return; } - else if (!strcmp(myARGV[2], "parent") && myARGC >= 5) + else if (!strcmp(myARGV[2], "parent") && myARGC >= 6) { - HANDLE h; + HANDLE h1, h2; - sscanf(myARGV[4], "%p", &h); - test_parent_process_attribute(atoi(myARGV[3]), h); + sscanf(myARGV[4], "%p", &h1); + sscanf(myARGV[5], "%p", &h2); + test_parent_process_attribute(atoi(myARGV[3]), h1, h2); return; } @@ -4136,5 +4171,5 @@ START_TEST(process) test_jobInheritance(job); test_BreakawayOk(job); CloseHandle(job); - test_parent_process_attribute(0, NULL); + test_parent_process_attribute(0, NULL, NULL); } -- 2.23.0