[PATCH v2 4/4] kernel32/tests: Test std handle inheritance in test_parent_process_attribute().

Paul Gofman gofmanp at gmail.com
Mon Dec 9 15:51:14 CST 2019


Signed-off-by: Paul Gofman <gofmanp at gmail.com>
---
    v2:
        - added test.

 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 4b18b70882..7ca38c63e9 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. */
@@ -3990,9 +4010,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());
@@ -4010,10 +4038,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);
@@ -4064,12 +4098,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;
         }
 
@@ -4138,5 +4173,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




More information about the wine-devel mailing list