From: Paul Gofman pgofman@codeweavers.com
Based on a patch by Nikolay Sivov. --- dlls/kernelbase/tests/process.c | 37 +++++++------ dlls/ntdll/tests/virtual.c | 95 +++++++++++++++------------------ dlls/ntdll/unix/virtual.c | 30 ++++++++++- 3 files changed, 90 insertions(+), 72 deletions(-)
diff --git a/dlls/kernelbase/tests/process.c b/dlls/kernelbase/tests/process.c index 14eed7d8fe9..f7b321cc09f 100644 --- a/dlls/kernelbase/tests/process.c +++ b/dlls/kernelbase/tests/process.c @@ -168,9 +168,7 @@ static void test_VirtualAlloc2(void)
/* Placeholder splitting functionality */ placeholder1 = pVirtualAlloc2(NULL, NULL, 2 * size, MEM_RESERVE_PLACEHOLDER | MEM_RESERVE, PAGE_NOACCESS, NULL, 0); - todo_wine ok(!!placeholder1, "Failed to create a placeholder range.\n"); - if (!placeholder1) return;
memset(&info, 0, sizeof(info)); VirtualQuery(placeholder1, &info, sizeof(info)); @@ -180,14 +178,14 @@ static void test_VirtualAlloc2(void) ok(info.RegionSize == 2 * size, "Unexpected size.\n");
ret = VirtualFree(placeholder1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); - ok(ret, "Failed to split placeholder.\n"); + todo_wine ok(ret, "Failed to split placeholder.\n");
memset(&info, 0, sizeof(info)); VirtualQuery(placeholder1, &info, sizeof(info)); ok(info.AllocationProtect == PAGE_NOACCESS, "Unexpected protection %#lx.\n", info.AllocationProtect); ok(info.State == MEM_RESERVE, "Unexpected state %#lx.\n", info.State); ok(info.Type == MEM_PRIVATE, "Unexpected type %#lx.\n", info.Type); - ok(info.RegionSize == size, "Unexpected size.\n"); + todo_wine ok(info.RegionSize == size, "Unexpected size.\n");
placeholder2 = (void *)((BYTE *)placeholder1 + size); memset(&info, 0, sizeof(info)); @@ -201,10 +199,10 @@ static void test_VirtualAlloc2(void) ok(!!section, "Failed to create a section.\n");
view1 = pMapViewOfFile3(section, NULL, placeholder1, 0, size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, NULL, 0); - ok(!!view1, "Failed to map a section.\n"); + todo_wine ok(!!view1, "Failed to map a section.\n");
view2 = pMapViewOfFile3(section, NULL, placeholder2, 0, size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, NULL, 0); - ok(!!view2, "Failed to map a section.\n"); + todo_wine ok(!!view2, "Failed to map a section.\n");
CloseHandle(section); UnmapViewOfFile(view1); @@ -220,16 +218,19 @@ static void test_VirtualAlloc2(void) p1 = p + size / 2; p2 = p1 + size / 4; ret = VirtualFree(p1, size / 4, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); - ok(ret, "Failed to split a placeholder.\n"); - check_region_size(p, size / 2); - check_region_size(p1, size / 4); + todo_wine ok(ret, "Failed to split a placeholder.\n"); + if (ret) + { + check_region_size(p, size / 2); + check_region_size(p1, size / 4); + } check_region_size(p2, 2 * size - size / 2 - size / 4); ret = VirtualFree(p, 0, MEM_RELEASE); ok(ret, "Failed to release a region.\n"); ret = VirtualFree(p1, 0, MEM_RELEASE); - ok(ret, "Failed to release a region.\n"); + todo_wine ok(ret, "Failed to release a region.\n"); ret = VirtualFree(p2, 0, MEM_RELEASE); - ok(ret, "Failed to release a region.\n"); + todo_wine ok(ret, "Failed to release a region.\n");
/* Split in two regions, specifying lower part. */ p = pVirtualAlloc2(NULL, NULL, 2 * size, MEM_RESERVE_PLACEHOLDER | MEM_RESERVE, PAGE_NOACCESS, NULL, 0); @@ -238,13 +239,14 @@ static void test_VirtualAlloc2(void) p1 = p; p2 = p + size / 2; ret = VirtualFree(p1, size / 2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); - ok(ret, "Failed to split a placeholder.\n"); - check_region_size(p1, size / 2); + todo_wine ok(ret, "Failed to split a placeholder.\n"); + if (ret) + check_region_size(p1, size / 2); check_region_size(p2, 2 * size - size / 2); ret = VirtualFree(p1, 0, MEM_RELEASE); ok(ret, "Failed to release a region.\n"); ret = VirtualFree(p2, 0, MEM_RELEASE); - ok(ret, "Failed to release a region.\n"); + todo_wine ok(ret, "Failed to release a region.\n");
/* Split in two regions, specifying second half. */ p = pVirtualAlloc2(NULL, NULL, 2 * size, MEM_RESERVE_PLACEHOLDER | MEM_RESERVE, PAGE_NOACCESS, NULL, 0); @@ -253,13 +255,14 @@ static void test_VirtualAlloc2(void) p1 = p; p2 = p + size; ret = VirtualFree(p2, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); - ok(ret, "Failed to split a placeholder.\n"); - check_region_size(p1, size); + todo_wine ok(ret, "Failed to split a placeholder.\n"); + if (ret) + check_region_size(p1, size); check_region_size(p2, size); ret = VirtualFree(p1, 0, MEM_RELEASE); ok(ret, "Failed to release a region.\n"); ret = VirtualFree(p2, 0, MEM_RELEASE); - ok(ret, "Failed to release a region.\n"); + todo_wine ok(ret, "Failed to release a region.\n"); }
static void test_VirtualAllocFromApp(void) diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index 2c8b1614b84..604e234b100 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -334,15 +334,11 @@ static void test_NtAllocateVirtualMemoryEx(void)
status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, NULL, 0); - todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
- if (addr1) - { - size = 0; - status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_RELEASE); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - } + size = 0; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
/* Placeholder region splitting. */
@@ -351,79 +347,72 @@ static void test_NtAllocateVirtualMemoryEx(void) size = 0x10000; status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, NULL, 0); - todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
+ p = addr1; + p1 = p + size / 2; + p2 = p1 + size / 4; + size2 = size / 4; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + if (status == STATUS_SUCCESS) { - p = addr1; - p1 = p + size / 2; - p2 = p1 + size / 4; - size2 = size / 4; - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - check_region_size(p, size / 2); check_region_size(p1, size / 4); - check_region_size(p2, size - size / 2 - size / 4); - - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p, &size2, MEM_RELEASE); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); } + check_region_size(p2, size - size / 2 - size / 4); + + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p, &size2, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
/* Split in two regions, specifying lower part. */ addr1 = NULL; size = 0x10000; status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, NULL, 0); - todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
- if (status == STATUS_SUCCESS) - { - p1 = addr1; - p2 = p1 + size / 4; - size2 = size / 4; - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - ok(p1 == addr1, "Unexpected address.\n"); + p1 = addr1; + p2 = p1 + size / 4; + size2 = size / 4; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(p1 == addr1, "Unexpected address.\n");
+ if (status == STATUS_SUCCESS) check_region_size(p1, size / 4); - check_region_size(p2, size - size / 4); - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - } + check_region_size(p2, size - size / 4); + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
/* Split in two regions, specifying second half. */ addr1 = NULL; size = 0x10000; status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, NULL, 0); - todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
- if (status == STATUS_SUCCESS) - { - p1 = addr1; - p2 = p1 + size / 2; + p1 = addr1; + p2 = p1 + size / 2;
- size2 = size / 2; - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - ok(p2 == p1 + size / 2, "Unexpected address.\n"); + size2 = size / 2; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(p2 == p1 + size / 2, "Unexpected address.\n"); + if (status == STATUS_SUCCESS) check_region_size(p1, size / 2); - check_region_size(p2, size / 2); - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - } + check_region_size(p2, size / 2); + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
memset( ext, 0, sizeof(ext) ); ext[0].Type = MemExtendedParameterAttributeFlags; diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 0ab9577d6a3..2aadb1def00 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -124,6 +124,8 @@ struct file_view #define VPROT_WRITEWATCH 0x40 /* per-mapping protection flags */ #define VPROT_SYSTEM 0x0200 /* system view (underlying mmap not under our control) */ +#define VPROT_PLACEHOLDER 0x0400 +#define VPROT_FREE_PLACEHOLDER 0x0800
/* Conversion from VPROT_* to Win32 flags */ static const BYTE VIRTUAL_Win32Flags[16] = @@ -1130,6 +1132,8 @@ static void dump_view( struct file_view *view ) TRACE( "View: %p - %p", addr, addr + view->size - 1 ); if (view->protect & VPROT_SYSTEM) TRACE( " (builtin image)\n" ); + else if (view->protect & VPROT_FREE_PLACEHOLDER) + TRACE( " (placeholder)\n" ); else if (view->protect & SEC_IMAGE) TRACE( " (image)\n" ); else if (view->protect & SEC_FILE) @@ -4071,8 +4075,7 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ
/* Compute the alloc type flags */
- if (!(type & (MEM_COMMIT | MEM_RESERVE | MEM_RESET)) || - (type & ~(MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN | MEM_WRITE_WATCH | MEM_RESET))) + if (!(type & (MEM_COMMIT | MEM_RESERVE | MEM_RESET))) { WARN("called with wrong alloc type flags (%08x) !\n", (int)type); return STATUS_INVALID_PARAMETER; @@ -4080,6 +4083,12 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ
if (!arm64ec_map && (attributes & MEM_EXTENDED_PARAMETER_EC_CODE)) return STATUS_INVALID_PARAMETER;
+ if (type & MEM_RESERVE_PLACEHOLDER && (protect != PAGE_NOACCESS)) + { + WARN( "Wrong protect %#x for placeholder.\n", (unsigned int)protect ); + return STATUS_INVALID_PARAMETER; + } + /* Reserve the memory */
server_enter_uninterrupted_section( &virtual_mutex, &sigset ); @@ -4090,6 +4099,7 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ { if (type & MEM_COMMIT) vprot |= VPROT_COMMITTED; if (type & MEM_WRITE_WATCH) vprot |= VPROT_WRITEWATCH; + if (type & MEM_RESERVE_PLACEHOLDER) vprot |= VPROT_PLACEHOLDER | VPROT_FREE_PLACEHOLDER; if (protect & PAGE_NOCACHE) vprot |= SEC_NOCACHE;
if (vprot & VPROT_WRITECOPY) status = STATUS_INVALID_PAGE_PROTECTION; @@ -4109,6 +4119,7 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ { if (!(view = find_view( base, size ))) status = STATUS_NOT_MAPPED_VIEW; else if (view->protect & SEC_FILE) status = STATUS_ALREADY_COMMITTED; + else if (view->protect & VPROT_FREE_PLACEHOLDER) status = STATUS_CONFLICTING_ADDRESSES; else if (!(status = set_protection( view, base, size, protect )) && (view->protect & SEC_RESERVE)) { SERVER_START_REQ( add_mapping_committed_range ) @@ -4144,6 +4155,7 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR zero_bits, SIZE_T *size_ptr, ULONG type, ULONG protect ) { + static const ULONG type_mask = MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN | MEM_WRITE_WATCH | MEM_RESET; ULONG_PTR limit;
TRACE("%p %p %08lx %x %08x\n", process, *ret, *size_ptr, (int)type, (int)protect ); @@ -4155,6 +4167,12 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR z if (!is_old_wow64() && zero_bits >= 32) return STATUS_INVALID_PARAMETER_3; #endif
+ if (type & ~type_mask) + { + WARN("Called with wrong alloc type flags %08x.\n", (int)type); + return STATUS_INVALID_PARAMETER; + } + if (process != NtCurrentProcess()) { apc_call_t call; @@ -4265,6 +4283,8 @@ NTSTATUS WINAPI NtAllocateVirtualMemoryEx( HANDLE process, PVOID *ret, SIZE_T *s ULONG protect, MEM_EXTENDED_PARAMETER *parameters, ULONG count ) { + static const ULONG type_mask = MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN | MEM_WRITE_WATCH + | MEM_RESET | MEM_RESERVE_PLACEHOLDER; ULONG_PTR limit = 0; ULONG_PTR align = 0; ULONG attributes = 0; @@ -4277,6 +4297,12 @@ NTSTATUS WINAPI NtAllocateVirtualMemoryEx( HANDLE process, PVOID *ret, SIZE_T *s status = get_extended_params( parameters, count, &limit, &align, &attributes, &machine ); if (status) return status;
+ if (type & ~type_mask) + { + WARN( "Called with wrong alloc type flags %08x.\n", (unsigned int)type ); + return STATUS_INVALID_PARAMETER; + } + if (*ret && (align || limit)) return STATUS_INVALID_PARAMETER; if (!*size_ptr) return STATUS_INVALID_PARAMETER;