[1/5] kernel: add VirtualAllocEx remote thread conformance tests
(updated)
Thomas Kho
tkho at ucla.edu
Wed Aug 16 03:56:01 CDT 2006
[1/5] kernel: add VirtualAllocEx remote thread conformance tests (updated)
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. If there are any issues, please let me know.
This patch is an update to a previously posted patch
(http://www.winehq.org/pipermail/wine-patches/2006-July/029259.html) that adds
a conformance test for VirtualAllocEx and VirtualFreeEx and also adds a small
stress test that runs for 0.5 seconds (or runs until stopped by user in
interactive mode).
Thomas Kho
---
dlls/kernel/tests/Makefile.in | 2
dlls/kernel/tests/virtual.c | 221 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 222 insertions(+), 1 deletions(-)
diff --git a/dlls/kernel/tests/Makefile.in b/dlls/kernel/tests/Makefile.in
index bfeae14..5f6c12e 100644
--- a/dlls/kernel/tests/Makefile.in
+++ b/dlls/kernel/tests/Makefile.in
@@ -3,7 +3,7 @@ TOPOBJDIR = ../../..
SRCDIR = @srcdir@
VPATH = @srcdir@
TESTDLL = kernel32.dll
-IMPORTS = kernel32
+IMPORTS = kernel32 user32
CTESTS = \
alloc.c \
diff --git a/dlls/kernel/tests/virtual.c b/dlls/kernel/tests/virtual.c
index 2eac5a7..9d9ffdc 100644
--- a/dlls/kernel/tests/virtual.c
+++ b/dlls/kernel/tests/virtual.c
@@ -19,12 +19,231 @@
*/
#include <stdarg.h>
+#include <stdio.h>
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
+#include "winuser.h"
#include "wine/test.h"
+#define NUM_THREADS 4
+
+HANDLE hStressTestProcess;
+HANDLE hStressTestQuitEvent;
+
+HANDLE create_process(char *program_name)
+{
+ DWORD d;
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si = { 0 };
+ si.cb = sizeof(si);
+
+ ok(CreateProcess(NULL, program_name, NULL, NULL, FALSE, 0, NULL, NULL,
+ &si, &pi) != 0, "error: %lu\n", GetLastError());
+ ok(CloseHandle(pi.hThread) != 0, "error %lu\n", GetLastError());
+ d = WaitForInputIdle(pi.hProcess, 5000);
+ ok(d == 0, "WaitForInputIdle returned %lu, last error %lu\n",
+ d, GetLastError());
+ return pi.hProcess;
+}
+
+void mini_stress_test(LPTHREAD_START_ROUTINE worker, char *name)
+{
+ HANDLE hThread[NUM_THREADS], hQuitEvent, hNotepad;
+ unsigned i;
+
+ hNotepad = create_process("notepad.exe");
+ ok(hNotepad != NULL, "Can't start notepad.exe\n");
+
+ hQuitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ ok(hQuitEvent != NULL, "Can't create event, err=%lu\n", GetLastError());
+
+ hStressTestProcess = hNotepad;
+ hStressTestQuitEvent = hQuitEvent;
+
+ 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(hQuitEvent);
+
+ 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(hNotepad, 0);
+ CloseHandle(hQuitEvent);
+ CloseHandle(hNotepad);
+}
+
+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_process("notepad.exe");
+ ok(hProcess != NULL, "Can't start notepad.exe\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 +482,8 @@ static void test_MapViewOfFile(void)
START_TEST(virtual)
{
+ test_VirtualAllocEx();
+ test_VirtualAllocEx_ministress();
test_VirtualAlloc();
test_MapViewOfFile();
}
More information about the wine-patches
mailing list