diff --git a/dlls/kernel32/tests/virtual.c b/dlls/kernel32/tests/virtual.c index 4f50df80e1c..15fc7158845 100644 --- a/dlls/kernel32/tests/virtual.c +++ b/dlls/kernel32/tests/virtual.c @@ -47,7 +47,10 @@ static struct _TEB * (WINAPI *pNtCurrentTeb)(void); static PVOID (WINAPI *pRtlAddVectoredExceptionHandler)(ULONG, PVECTORED_EXCEPTION_HANDLER); static ULONG (WINAPI *pRtlRemoveVectoredExceptionHandler)(PVOID); static BOOL (WINAPI *pGetProcessDEPPolicy)(HANDLE, LPDWORD, PBOOL); +static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL); static NTSTATUS (WINAPI *pNtProtectVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG, ULONG *); +static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG, SIZE_T *, ULONG, ULONG); +static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG); /* ############################### */ @@ -237,6 +240,8 @@ static void test_VirtualAlloc(void) void *addr1, *addr2; DWORD old_prot; MEMORY_BASIC_INFORMATION info; + NTSTATUS status; + SIZE_T size; SetLastError(0xdeadbeef); addr1 = VirtualAlloc(0, 0, MEM_RESERVE, PAGE_NOACCESS); @@ -372,6 +377,42 @@ static void test_VirtualAlloc(void) "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError()); ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n"); + + addr1 = VirtualAlloc(0, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + ok(addr1 != NULL, "VirtualAlloc failed\n"); + ok(!((ULONG_PTR)addr1 & 0xffff), "returned memory %p is not aligned to 64k\n", addr1); + + /* allocation conflicts because of 64k align */ + size = 0x1000; + addr2 = (char *)addr1 + 0x1000; + status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 0, &size, + MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + ok(status == STATUS_CONFLICTING_ADDRESSES, "NtAllocateVirtualMemory returned %08x\n", status); + + /* it should conflict, even when zero_bits is explicitly set */ + size = 0x1000; + addr2 = (char *)addr1 + 0x1000; + status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 12, &size, + MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + todo_wine + ok(status == STATUS_CONFLICTING_ADDRESSES, "NtAllocateVirtualMemory returned %08x\n", status); + if (status == STATUS_SUCCESS) ok(VirtualFree(addr2, 0, MEM_RELEASE), "VirtualFree failed\n"); + + /* AT_ROUND_TO_PAGE flag is not supported for VirtualAlloc */ + SetLastError(0xdeadbeef); + addr2 = VirtualAlloc(addr1, 0x1000, MEM_RESERVE | MEM_COMMIT | AT_ROUND_TO_PAGE, PAGE_EXECUTE_READWRITE); + ok(!addr2, "VirtualAlloc unexpectedly succeeded\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError()); + + /* AT_ROUND_TO_PAGE flag is not supported for NtAllocateVirtualMemory */ + size = 0x1000; + addr2 = (char *)addr1 + 0x1000; + status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 0, &size, MEM_RESERVE | + MEM_COMMIT | AT_ROUND_TO_PAGE, PAGE_EXECUTE_READWRITE); + todo_wine + ok(status == STATUS_INVALID_PARAMETER_5, "NtAllocateVirtualMemory returned %08x\n", status); + + ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n"); } static void test_MapViewOfFile(void) @@ -957,8 +998,8 @@ static void test_NtMapViewOfSection(void) static const char data[] = "test data for NtMapViewOfSection"; char buffer[sizeof(data)]; HANDLE file, mapping; - void *ptr; - BOOL ret; + void *ptr, *ptr2; + BOOL is_wow64, ret; DWORD status, written; SIZE_T size, result; LARGE_INTEGER offset; @@ -988,12 +1029,165 @@ static void test_NtMapViewOfSection(void) offset.QuadPart = 0; status = pNtMapViewOfSection( mapping, hProcess, &ptr, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE ); ok( !status, "NtMapViewOfSection failed status %x\n", status ); + ok( !((ULONG_PTR)ptr & 0xffff), "returned memory %p is not aligned to 64k\n", ptr ); ret = ReadProcessMemory( hProcess, ptr, buffer, sizeof(buffer), &result ); ok( ret, "ReadProcessMemory failed\n" ); ok( result == sizeof(buffer), "ReadProcessMemory didn't read all data (%lx)\n", result ); ok( !memcmp( buffer, data, sizeof(buffer) ), "Wrong data read\n" ); + /* for some unknown reason NtMapViewOfSection fails with STATUS_NO_MEMORY when zero_bits != 0 ? */ + ptr2 = NULL; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 12, 0, &offset, &size, 1, 0, PAGE_READWRITE ); + todo_wine + ok( status == STATUS_NO_MEMORY, "NtMapViewOfSection returned %x\n", status ); + if (status == STATUS_SUCCESS) + { + status = pNtUnmapViewOfSection( hProcess, ptr2 ); + ok( !status, "NtUnmapViewOfSection failed status %x\n", status ); + } + + ptr2 = NULL; + size = 0; + status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 16, 0, &offset, &size, 1, 0, PAGE_READWRITE ); + todo_wine + ok( status == STATUS_NO_MEMORY, "NtMapViewOfSection returned %x\n", status ); + if (status == STATUS_SUCCESS) + { + status = pNtUnmapViewOfSection( hProcess, ptr2 ); + ok( !status, "NtUnmapViewOfSection failed status %x\n", status ); + } + + /* mapping at the same page conflicts */ + ptr2 = ptr; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE ); + ok( status == STATUS_CONFLICTING_ADDRESSES, "NtMapViewOfSection returned %x\n", status ); + + /* offset has to be aligned */ + ptr2 = ptr; + size = 0; + offset.QuadPart = 1; + status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE ); + todo_wine + ok( status == STATUS_MAPPED_ALIGNMENT, "NtMapViewOfSection returned %x\n", status ); + + /* ptr has to be aligned */ + ptr2 = (char *)ptr + 42; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE ); + todo_wine + ok( status == STATUS_MAPPED_ALIGNMENT, "NtMapViewOfSection returned %x\n", status ); + + /* still not 64k aligned */ + ptr2 = (char *)ptr + 0x1000; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE ); + todo_wine + ok( status == STATUS_MAPPED_ALIGNMENT, "NtMapViewOfSection returned %x\n", status ); + + /* zero_bits != 0 is not allowed when an address is set */ + ptr2 = (char *)ptr + 0x1000; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 12, 0, &offset, &size, 1, 0, PAGE_READWRITE ); + todo_wine + ok( status == STATUS_INVALID_PARAMETER_4, "NtMapViewOfSection returned %x\n", status ); + if (status == STATUS_SUCCESS) + { + status = pNtUnmapViewOfSection( hProcess, ptr2 ); + ok( !status, "NtUnmapViewOfSection failed status %x\n", status ); + } + + ptr2 = (char *)ptr + 0x1000; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 16, 0, &offset, &size, 1, 0, PAGE_READWRITE ); + todo_wine + ok( status == STATUS_INVALID_PARAMETER_4, "NtMapViewOfSection returned %x\n", status ); + if (status == STATUS_SUCCESS) + { + status = pNtUnmapViewOfSection( hProcess, ptr2 ); + ok( !status, "NtUnmapViewOfSection failed status %x\n", status ); + } + + if (sizeof(void *) == sizeof(int) && (!pIsWow64Process || + !pIsWow64Process( GetCurrentProcess(), &is_wow64 ) || !is_wow64)) + { + /* new memory region conflicts with previous mapping */ + ptr2 = ptr; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, + &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE ); + ok( status == STATUS_CONFLICTING_ADDRESSES, "NtMapViewOfSection returned %x\n", status ); + + ptr2 = (char *)ptr + 42; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, + &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE ); + todo_wine + ok( status == STATUS_CONFLICTING_ADDRESSES, "NtMapViewOfSection returned %x\n", status ); + + /* in contrary to regular NtMapViewOfSection, only 4kb align is enforced */ + ptr2 = (char *)ptr + 0x1000; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, + &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE ); + todo_wine + ok( status == STATUS_SUCCESS, "NtMapViewOfSection returned %x\n", status ); + ok( (char *)ptr2 == (char *)ptr + 0x1000, + "expected address %p, got %p\n", (char *)ptr + 0x1000, ptr2 ); + status = pNtUnmapViewOfSection( hProcess, ptr2 ); + todo_wine + ok( !status, "NtUnmapViewOfSection failed status %x\n", status ); + + /* the address is rounded down if not on a page boundary */ + ptr2 = (char *)ptr + 0x1001; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, + &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE ); + todo_wine + ok( status == STATUS_SUCCESS, "NtMapViewOfSection returned %x\n", status ); + todo_wine + ok( (char *)ptr2 == (char *)ptr + 0x1000, + "expected address %p, got %p\n", (char *)ptr + 0x1000, ptr2 ); + status = pNtUnmapViewOfSection( hProcess, ptr2 ); + todo_wine + ok( !status, "NtUnmapViewOfSection failed status %x\n", status ); + + ptr2 = (char *)ptr + 0x2000; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, + &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE ); + todo_wine + ok( status == STATUS_SUCCESS, "NtMapViewOfSection returned %x\n", status ); + ok( (char *)ptr2 == (char *)ptr + 0x2000, + "expected address %p, got %p\n", (char *)ptr + 0x2000, ptr2 ); + status = pNtUnmapViewOfSection( hProcess, ptr2 ); + todo_wine + ok( !status, "NtUnmapViewOfSection failed status %x\n", status ); + } + else + { + ptr2 = (char *)ptr + 0x1000; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, + &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE ); + todo_wine + ok( status == STATUS_INVALID_PARAMETER_9, "NtMapViewOfSection returned %x\n", status ); + } + status = pNtUnmapViewOfSection( hProcess, ptr ); ok( !status, "NtUnmapViewOfSection failed status %x\n", status ); @@ -3495,6 +3689,7 @@ START_TEST(virtual) pGetWriteWatch = (void *) GetProcAddress(hkernel32, "GetWriteWatch"); pResetWriteWatch = (void *) GetProcAddress(hkernel32, "ResetWriteWatch"); pGetProcessDEPPolicy = (void *)GetProcAddress( hkernel32, "GetProcessDEPPolicy" ); + pIsWow64Process = (void *)GetProcAddress( hkernel32, "IsWow64Process" ); pNtAreMappedFilesTheSame = (void *)GetProcAddress( hntdll, "NtAreMappedFilesTheSame" ); pNtMapViewOfSection = (void *)GetProcAddress( hntdll, "NtMapViewOfSection" ); pNtUnmapViewOfSection = (void *)GetProcAddress( hntdll, "NtUnmapViewOfSection" ); @@ -3502,6 +3697,8 @@ START_TEST(virtual) pRtlAddVectoredExceptionHandler = (void *)GetProcAddress( hntdll, "RtlAddVectoredExceptionHandler" ); pRtlRemoveVectoredExceptionHandler = (void *)GetProcAddress( hntdll, "RtlRemoveVectoredExceptionHandler" ); pNtProtectVirtualMemory = (void *)GetProcAddress( hntdll, "NtProtectVirtualMemory" ); + pNtAllocateVirtualMemory = (void *)GetProcAddress( hntdll, "NtAllocateVirtualMemory" ); + pNtFreeVirtualMemory = (void *)GetProcAddress( hntdll, "NtFreeVirtualMemory" ); test_shared_memory(FALSE); test_shared_memory_ro(FALSE, FILE_MAP_READ|FILE_MAP_WRITE); diff --git a/include/winnt.h b/include/winnt.h index 7a08810330d..fcf65f22b9b 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -736,6 +736,7 @@ typedef struct _MEMORY_BASIC_INFORMATION #define WRITE_WATCH_FLAG_RESET 0x00000001 +#define AT_ROUND_TO_PAGE 0x40000000 #define MINCHAR 0x80 #define MAXCHAR 0x7f