[1/5] kernel: add VirtualAllocEx remote thread conformance tests (update 2)

Thomas Kho tkho at ucla.edu
Fri Aug 18 03:25:28 CDT 2006


[1/5] kernel: add VirtualAllocEx remote thread conformance tests (update 2)

This set of 5 patches brings together a pair of conformance tests I had
previously sent and the APC implementation of remote process operations I have
more recently sent.

This patch is updated to remove a dependency on user32 and does remote
operations on itself (like the process tests)  instead of notepad.exe

Thomas Kho

---

 dlls/kernel/tests/virtual.c |  243 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 243 insertions(+), 0 deletions(-)

diff --git a/dlls/kernel/tests/virtual.c b/dlls/kernel/tests/virtual.c
index 2eac5a7..75dd0d6 100644
--- a/dlls/kernel/tests/virtual.c
+++ b/dlls/kernel/tests/virtual.c
@@ -19,12 +19,227 @@
  */
 
 #include <stdarg.h>
+#include <stdio.h>
 
 #include "windef.h"
 #include "winbase.h"
 #include "winerror.h"
 #include "wine/test.h"
 
+#define NUM_THREADS 4
+
+HANDLE hStressTestProcess;
+HANDLE hStressTestQuitEvent;
+
+HANDLE create_target_process(char *arg)
+{
+    char **argv;
+    char cmdline[MAX_PATH];
+    PROCESS_INFORMATION pi;
+    STARTUPINFO si = { 0 };
+    si.cb = sizeof(si);
+
+    winetest_get_mainargs( &argv );
+    sprintf(cmdline, "%s %s %s", argv[0], argv[1], arg);
+    ok(CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL,
+                     &si, &pi) != 0, "error: %lu\n", GetLastError());
+    ok(CloseHandle(pi.hThread) != 0, "error %lu\n", GetLastError());
+    return pi.hProcess;
+}
+
+void mini_stress_test(LPTHREAD_START_ROUTINE worker, char *name)
+{
+    HANDLE hThread[NUM_THREADS];
+    unsigned i;
+
+    hStressTestProcess = create_target_process("stress");
+    ok(hStressTestProcess!= NULL, "Can't start process\n");
+
+    hStressTestQuitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+    ok(hStressTestQuitEvent != NULL, "Can't create event, err=%lu\n", GetLastError());
+
+    for (i = 0; i < NUM_THREADS; i++)
+    {
+        hThread[i] = CreateThread(NULL, 0, worker, NULL, 0, NULL);
+        ok(hThread[i] != NULL, "CreateThread error %lu\n", GetLastError());
+    }
+
+    if (winetest_interactive)
+    {
+        printf("Press return to end %s stress test", name);
+        getchar();
+    }
+    else /* run stress test for 500ms */
+        Sleep(500);
+
+    SetEvent(hStressTestQuitEvent);
+
+    for (i = 0; i < NUM_THREADS; i++)
+    {
+        ok(WaitForSingleObject(hThread[i], 200) == WAIT_OBJECT_0,
+           "Thread %d not yet ended\n", i);
+        CloseHandle(hThread[i]);
+    }
+
+    TerminateProcess(hStressTestProcess, 0);
+    CloseHandle(hStressTestQuitEvent);
+    CloseHandle(hStressTestProcess);
+}
+
+static void test_VirtualAllocEx(void)
+{
+    const unsigned int alloc_size = 1<<15;
+    char *src, *dst;
+    unsigned long bytes_written = 0, bytes_read = 0, i;
+    void *addr1, *addr2;
+    BOOL b;
+    DWORD old_prot;
+    MEMORY_BASIC_INFORMATION info;
+    HANDLE hProcess;
+
+    hProcess = create_target_process("sleep");
+    ok(hProcess != NULL, "Can't start process\n");
+
+    src = (char *) HeapAlloc( GetProcessHeap(), 0, alloc_size );
+    dst = (char *) HeapAlloc( GetProcessHeap(), 0, alloc_size );
+    for (i = 0; i < alloc_size; i++)
+        src[i] = 0xcafedead + i;
+
+    addr1 = VirtualAllocEx(hProcess, NULL, alloc_size, MEM_COMMIT,
+                           PAGE_EXECUTE_READWRITE);
+    todo_wine ok(addr1 != NULL, "VirtualAllocEx error %lu\n", GetLastError());
+    b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written);
+    ok(b && (bytes_written == alloc_size), "%lu bytes written\n",
+       bytes_written);
+    b = ReadProcessMemory(hProcess, addr1, dst, alloc_size, &bytes_read);
+    ok(b && (bytes_read == alloc_size), "%lu bytes read\n", bytes_read);
+    ok(!memcmp(src, dst, alloc_size), "Data from remote process differs\n");
+    b = VirtualFreeEx(hProcess, addr1, 0, MEM_RELEASE);
+    todo_wine ok(b != 0, "VirtualFreeEx, error %lu\n", GetLastError());
+
+    HeapFree( GetProcessHeap(), 0, src );
+    HeapFree( GetProcessHeap(), 0, dst );
+
+    /*
+     * The following tests parallel those in test_VirtualAlloc()
+     */
+
+    SetLastError(0xdeadbeef);
+    addr1 = VirtualAllocEx(hProcess, 0, 0, MEM_RESERVE, PAGE_NOACCESS);
+    ok(addr1 == NULL, "VirtualAllocEx should fail on zero-sized allocation\n");
+    ok(GetLastError() == ERROR_INVALID_PARAMETER /* NT */ ||
+       GetLastError() == ERROR_NOT_ENOUGH_MEMORY, /* Win9x */
+        "got %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
+
+    addr1 = VirtualAllocEx(hProcess, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
+    todo_wine ok(addr1 != NULL, "VirtualAllocEx failed\n");
+
+    /* test a not committed memory */
+    memset(&info, 'q', sizeof(info));
+    todo_wine ok(VirtualQueryEx(hProcess, addr1, &info, sizeof(info))
+                 == sizeof(info), "VirtualQueryEx failed\n");
+    todo_wine ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress,
+                 addr1);
+    todo_wine ok(info.AllocationBase == addr1, "%p != %p\n",
+                 info.AllocationBase, addr1);
+    todo_wine ok(info.AllocationProtect == PAGE_NOACCESS,
+                 "%lx != PAGE_NOACCESS\n", info.AllocationProtect);
+    todo_wine ok(info.RegionSize == 0x10000, "%lx != 0x10000\n",
+                 info.RegionSize);
+    todo_wine ok(info.State == MEM_RESERVE, "%lx != MEM_RESERVE\n", info.State);
+    /* NT reports Protect == 0 for a not committed memory block */
+    todo_wine ok(info.Protect == 0 /* NT */ ||
+       info.Protect == PAGE_NOACCESS, /* Win9x */
+        "%lx != PAGE_NOACCESS\n", info.Protect);
+    todo_wine ok(info.Type == MEM_PRIVATE, "%lx != MEM_PRIVATE\n", info.Type);
+
+    SetLastError(0xdeadbeef);
+    ok(!VirtualProtectEx(hProcess, addr1, 0xFFFC, PAGE_READONLY, &old_prot),
+       "VirtualProtectEx should fail on a not committed memory\n");
+    todo_wine ok(GetLastError() == ERROR_INVALID_ADDRESS /* NT */ ||
+       GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x */
+        "got %ld, expected ERROR_INVALID_ADDRESS\n", GetLastError());
+
+    addr2 = VirtualAllocEx(hProcess, addr1, 0x1000, MEM_COMMIT, PAGE_NOACCESS);
+    ok(addr1 == addr2, "VirtualAllocEx failed\n");
+
+    /* test a committed memory */
+    todo_wine ok(VirtualQueryEx(hProcess, addr1, &info, sizeof(info))
+                 == sizeof(info),
+        "VirtualQueryEx failed\n");
+    todo_wine ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress,
+                 addr1);
+    todo_wine ok(info.AllocationBase == addr1, "%p != %p\n",
+                 info.AllocationBase, addr1);
+    todo_wine ok(info.AllocationProtect == PAGE_NOACCESS,
+                 "%lx != PAGE_NOACCESS\n", info.AllocationProtect);
+    todo_wine ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize);
+    todo_wine ok(info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State);
+    /* this time NT reports PAGE_NOACCESS as well */
+    todo_wine ok(info.Protect == PAGE_NOACCESS, "%lx != PAGE_NOACCESS\n",
+                 info.Protect);
+    todo_wine ok(info.Type == MEM_PRIVATE, "%lx != MEM_PRIVATE\n", info.Type);
+
+    /* this should fail, since not the whole range is committed yet */
+    SetLastError(0xdeadbeef);
+    ok(!VirtualProtectEx(hProcess, addr1, 0xFFFC, PAGE_READONLY, &old_prot),
+        "VirtualProtectEx should fail on a not committed memory\n");
+    todo_wine ok(GetLastError() == ERROR_INVALID_ADDRESS /* NT */ ||
+       GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x */
+        "got %ld, expected ERROR_INVALID_ADDRESS\n", GetLastError());
+
+    todo_wine ok(VirtualProtectEx(hProcess, addr1, 0x1000, PAGE_READONLY,
+                                  &old_prot), "VirtualProtectEx failed\n");
+    todo_wine ok(old_prot == PAGE_NOACCESS,
+        "wrong old protection: got %04lx instead of PAGE_NOACCESS\n", old_prot);
+
+    todo_wine ok(VirtualProtectEx(hProcess, addr1, 0x1000, PAGE_READWRITE,
+                                  &old_prot), "VirtualProtectEx failed\n");
+    todo_wine ok(old_prot == PAGE_READONLY,
+        "wrong old protection: got %04lx instead of PAGE_READONLY\n", old_prot);
+
+    ok(!VirtualFreeEx(hProcess, addr1, 0x10000, 0),
+       "VirtualFreeEx should fail with type 0\n");
+    todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER,
+        "got %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
+
+    todo_wine ok(VirtualFreeEx(hProcess, addr1, 0x10000, MEM_DECOMMIT),
+                 "VirtualFreeEx failed\n");
+
+    /* if the type is MEM_RELEASE, size must be 0 */
+    ok(!VirtualFreeEx(hProcess, addr1, 1, MEM_RELEASE),
+       "VirtualFreeEx should fail\n");
+    todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER,
+        "got %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
+
+    todo_wine ok(VirtualFreeEx(hProcess, addr1, 0, MEM_RELEASE),
+                 "VirtualFreeEx failed\n");
+
+    TerminateProcess(hProcess, 0);
+    CloseHandle(hProcess);
+}
+
+static DWORD WINAPI create_virtualallocex_worker(LPVOID lpParameter)
+{
+    while (WaitForSingleObject(hStressTestQuitEvent, 0) != WAIT_OBJECT_0)
+    {
+        VOID *mem;
+        mem = VirtualAllocEx(hStressTestProcess, NULL, 1<<20,
+                             MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+        todo_wine ok(mem != NULL, "VirtualAllocEx error %lu\n", GetLastError());
+        todo_wine ok(VirtualFreeEx(hStressTestProcess, mem, 0, MEM_RELEASE) != 0,
+                     "VirtualFreeEx error %lu\n", GetLastError());
+        if (!mem) break;
+    }
+    return 0;
+}
+
+/* mini stress test for CreateRemoteThread */
+static VOID test_VirtualAllocEx_ministress(void)
+{
+    mini_stress_test(create_virtualallocex_worker, "VirtualAllocEx");
+}
+
 static void test_VirtualAlloc(void)
 {
     void *addr1, *addr2;
@@ -263,6 +478,34 @@ static void test_MapViewOfFile(void)
 
 START_TEST(virtual)
 {
+    int argc;
+    char **argv;
+    argc = winetest_get_mainargs( &argv );
+
+    if (argc >= 3)
+    {
+        if (!strcmp(argv[2], "sleep"))
+        {
+            Sleep(5000); /* spawned process runs for at most 5 seconds */
+            return;
+        }
+        while (1)
+        {
+            void *mem;
+            BOOL ret;
+            mem = VirtualAlloc(NULL, 1<<20, MEM_COMMIT|MEM_RESERVE,
+                               PAGE_EXECUTE_READWRITE);
+            ok(mem != NULL, "VirtualAlloc failed %lu\n", GetLastError());
+            if (mem == NULL) break;
+            ret = VirtualFree(mem, 0, MEM_RELEASE);
+            ok(ret, "VirtualFree failed %lu\n", GetLastError());
+            if (!ret) break;
+        }
+        return;
+    }
+
+    test_VirtualAllocEx();
+    test_VirtualAllocEx_ministress();
     test_VirtualAlloc();
     test_MapViewOfFile();
 }



More information about the wine-patches mailing list