[PATCH v5 1/2] kernel32/tests: Add test suite to modify the thread, order of toolhelp.

Changping Yu dead.ash at hotmail.com
Sun Jun 28 03:56:08 CDT 2020


>From 3df24c15b2addeade1776771e4918546103953ac Mon Sep 17 00:00:00 2001
From: Changping Yu <dead.ash at hotmail.com>
Date: Sun, 28 Jun 2020 16:24:10 +0800
Subject: [PATCH v5 1/2] kernel32/tests: Add test suite to modify the thread
 order of toolhelp.

v5: Add NtQuerySystemInformation function to get the test of thread order

Some software incorrectly uses the way to get the main thread id.
Coincidentally, the threads of wine and windows return differently.
The list of threads returned by flipping can be consistent with windows.

Signed-off-by: Changping Yu <dead.ash at hotmail.com>
---
 dlls/kernel32/tests/toolhelp.c | 174 ++++++++++++++++++++++++++++++++-
 1 file changed, 173 insertions(+), 1 deletion(-)

diff --git a/dlls/kernel32/tests/toolhelp.c b/dlls/kernel32/tests/toolhelp.c
index 9250f8dc54..61df560179 100644
--- a/dlls/kernel32/tests/toolhelp.c
+++ b/dlls/kernel32/tests/toolhelp.c
@@ -22,11 +22,14 @@
 #include <stdlib.h>
 #include <stdio.h>
 
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #include "windef.h"
 #include "winbase.h"
 #include "tlhelp32.h"
 #include "wine/test.h"
 #include "winuser.h"
+#include "winternl.h"
 
 static char     selfname[MAX_PATH];
 
@@ -38,9 +41,12 @@ static BOOL (WINAPI *pProcess32First)(HANDLE, LPPROCESSENTRY32);
 static BOOL (WINAPI *pProcess32Next)(HANDLE, LPPROCESSENTRY32);
 static BOOL (WINAPI *pThread32First)(HANDLE, LPTHREADENTRY32);
 static BOOL (WINAPI *pThread32Next)(HANDLE, LPTHREADENTRY32);
+static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, void *, ULONG, ULONG *);
 
 /* 1 minute should be more than enough */
 #define WAIT_TIME       (60 * 1000)
+/* Specify the number of simultaneous threads to test */
+#define NUM_THREADS 4
 
 static DWORD WINAPI sub_thread(void* pmt)
 {
@@ -150,6 +156,168 @@ static void test_process(DWORD curr_pid, DWORD sub_pcs_pid)
     ok(!pProcess32First( hSnapshot, &pe ), "shouldn't return a process\n");
 }
 
+static DWORD WINAPI get_id_thread(void* curr_pid)
+{
+    HANDLE              hSnapshot;
+    THREADENTRY32       te;
+    HANDLE              ev, threads[NUM_THREADS];
+    DWORD               thread_ids[NUM_THREADS];
+    DWORD               thread_traversed[NUM_THREADS];
+    DWORD               tid, first_tid = 0;
+    BOOL                found = FALSE;
+    int                 matched_idx = -1;
+    ULONG               buf_size = 0x1000;
+    NTSTATUS            nts;
+    void*               pcs_buffer = NULL;
+
+    ev = CreateEventW(NULL, FALSE, FALSE, NULL);
+    ok(ev != NULL, "Cannot create event\n");
+
+    for (int i = 0; i < NUM_THREADS; i++)
+    {
+        threads[i] = CreateThread(NULL, 0, sub_thread, ev, 0, &tid);
+        ok(threads[i] != NULL, "Cannot create thread\n");
+        thread_ids[i] = tid;
+    }
+
+    hSnapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
+    ok(hSnapshot != NULL, "Cannot create snapshot\n");
+
+    /* check that this current process is enumerated */
+    te.dwSize = sizeof(te);
+    ok(pThread32First(hSnapshot, &te), "Thread cannot traverse\n");
+    do
+    {
+        if (found)
+        {
+            if (te.th32OwnerProcessID != (DWORD)curr_pid) break;
+
+            if (matched_idx >= 0)
+            {
+                thread_traversed[matched_idx++] = te.th32ThreadID;
+                if (matched_idx >= NUM_THREADS) break;
+            }
+            else if (thread_ids[0] == te.th32ThreadID)
+            {
+                matched_idx = 0;
+                thread_traversed[matched_idx++] = te.th32ThreadID;
+            }
+        }
+        else if (te.th32OwnerProcessID == (DWORD)curr_pid) 
+        {
+            found = TRUE;
+            first_tid = te.th32ThreadID;
+        }
+    }
+    while (pThread32Next(hSnapshot, &te));
+
+    ok(found, "couldn't find self and/or sub-process in process list\n");
+
+    /* Check if the thread order is strictly consistent */
+    found = FALSE;
+    for (int i = 0; i < NUM_THREADS; i++)
+    {
+        if (thread_traversed[i] != thread_ids[i])
+        {
+            found = TRUE;
+            break;
+        }
+    }
+    todo_wine
+    ok(found==FALSE, "The thread order is not strictly consistent\n");
+
+    /* Determine the order by NtQuerySystemInformation function */
+    pcs_buffer = HeapAlloc(GetProcessHeap(), 0, buf_size);
+    ok(pcs_buffer!=NULL, "Unable to allocate space\n");
+    found = FALSE;
+    matched_idx = -1;
+    for (;;)
+    {
+        nts = NtQuerySystemInformation(SystemProcessInformation,
+                                       pcs_buffer, buf_size, NULL);
+        if (nts != STATUS_INFO_LENGTH_MISMATCH) break;
+        pcs_buffer = HeapReAlloc(GetProcessHeap(), 0, pcs_buffer, buf_size *= 2);
+        if (!pcs_buffer) break;
+    }
+    ok(pcs_buffer!=NULL, "Unable to allocate space\n");
+
+    if (nts == STATUS_SUCCESS)
+    {
+        SYSTEM_PROCESS_INFORMATION*     spi = pcs_buffer;
+        for (;;)
+        {
+            if (HandleToUlong(spi->UniqueProcessId) == (DWORD)curr_pid)
+            {
+                // thread_traversed[0] = 0;
+                for (int i = 0; i < spi->dwThreadCount; i++)
+                {
+                    tid = HandleToULong(spi->ti[i].ClientId.UniqueThread);
+
+                    if (matched_idx >= 0)
+                    {
+                        thread_traversed[matched_idx++] = te.th32ThreadID;
+                        if (matched_idx >= NUM_THREADS) break;
+                    }
+                    else if (thread_ids[0] == te.th32ThreadID)
+                    {
+                        matched_idx = 0;
+                        thread_traversed[matched_idx++] = te.th32ThreadID;
+                    }
+                }
+                found = TRUE;
+                break;
+            }
+            if (!spi->NextEntryOffset) break;
+            spi = (SYSTEM_PROCESS_INFORMATION*)((char*)spi + spi->NextEntryOffset);
+        }
+    }
+
+    ok(found, "Unsuccessful traversal\n");
+    if (found)
+    {
+        found = FALSE;
+        for (int i = 0; i < NUM_THREADS; i++)
+        {
+            if (thread_traversed[i] != thread_ids[i])
+            {
+                found = TRUE;
+                break;
+            }
+        }
+        todo_wine
+        ok(found==FALSE, "Judge the failure of traversing thread by NtQuerySystemInformation function\n");
+    }
+
+    SetEvent(ev);
+    for (int i = 0; i < NUM_THREADS; i++)
+        CloseHandle(threads[i]);
+    CloseHandle(ev);
+    CloseHandle(hSnapshot);
+
+    return first_tid;
+}
+
+static void test_main_thread(DWORD curr_pid, DWORD main_tid)
+{
+    HANDLE              thread;
+    DWORD               tid, first_tid = 0;
+    int                 error;
+
+    /* check that the main thread id is first one in this thread. */
+    first_tid = get_id_thread((void *)curr_pid);
+    todo_wine
+    ok(first_tid == main_tid, "check main thread is error, main is %d, %d\n", main_tid, first_tid);
+
+    /* check that the main thread id is first one in other thread. */
+    thread = CreateThread(NULL, 0, get_id_thread, (void *)curr_pid, 0, &tid);
+    error = WaitForSingleObject(thread, 10000);
+    ok(error == WAIT_OBJECT_0, "Thread did not complete within timelimit\n");
+
+    ok(GetExitCodeThread(thread, &first_tid), "Could not retrieve ext code\n");
+    todo_wine
+    ok(first_tid == main_tid, "check main thread is error, main is %d, %d\n", main_tid, first_tid);
+}
+
 static void test_thread(DWORD curr_pid, DWORD sub_pcs_pid)
 {
     HANDLE              hSnapshot;
@@ -291,6 +459,7 @@ START_TEST(toolhelp)
     HANDLE              ev1, ev2;
     DWORD               w;
     HANDLE              hkernel32 = GetModuleHandleA("kernel32");
+    HANDLE              hntdll = GetModuleHandleA("ntdll.dll");
 
     pCreateToolhelp32Snapshot = (VOID *) GetProcAddress(hkernel32, "CreateToolhelp32Snapshot");
     pModule32First = (VOID *) GetProcAddress(hkernel32, "Module32First");
@@ -299,11 +468,13 @@ START_TEST(toolhelp)
     pProcess32Next = (VOID *) GetProcAddress(hkernel32, "Process32Next");
     pThread32First = (VOID *) GetProcAddress(hkernel32, "Thread32First");
     pThread32Next = (VOID *) GetProcAddress(hkernel32, "Thread32Next");
+    pNtQuerySystemInformation = (VOID *) GetProcAddress(hntdll, "NtQuerySystemInformation");
 
     if (!pCreateToolhelp32Snapshot || 
         !pModule32First || !pModule32Next ||
         !pProcess32First || !pProcess32Next ||
-        !pThread32First || !pThread32Next)
+        !pThread32First || !pThread32Next ||
+        !pNtQuerySystemInformation)
     {
         win_skip("Needed functions are not available, most likely running on Windows NT\n");
         return;
@@ -339,6 +510,7 @@ START_TEST(toolhelp)
 
     test_process(pid, info.dwProcessId);
     test_thread(pid, info.dwProcessId);
+    test_main_thread(pid, GetCurrentThreadId());
     test_module(pid, curr_expected_modules, ARRAY_SIZE(curr_expected_modules));
     test_module(info.dwProcessId, sub_expected_modules, ARRAY_SIZE(sub_expected_modules));
 
-- 
2.27.0.windows.1



More information about the wine-devel mailing list