Commit 4142d1e0 authored by Paul Gofman's avatar Paul Gofman Committed by Alexandre Julliard

ntdll: Support MEM_PRESERVE_PLACEHOLDER in NtFreeVirtualMemory().

parent 04e2b02a
......@@ -178,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);
todo_wine ok(ret, "Failed to split placeholder.\n");
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);
todo_wine ok(info.RegionSize == size, "Unexpected size.\n");
ok(info.RegionSize == size, "Unexpected size.\n");
placeholder2 = (void *)((BYTE *)placeholder1 + size);
memset(&info, 0, sizeof(info));
......@@ -199,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);
todo_wine ok(!!view1, "Failed to map a section.\n");
ok(!!view1, "Failed to map a section.\n");
view2 = pMapViewOfFile3(section, NULL, placeholder2, 0, size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, NULL, 0);
todo_wine ok(!!view2, "Failed to map a section.\n");
ok(!!view2, "Failed to map a section.\n");
CloseHandle(section);
UnmapViewOfFile(view1);
......@@ -218,19 +218,16 @@ static void test_VirtualAlloc2(void)
p1 = p + size / 2;
p2 = p1 + size / 4;
ret = VirtualFree(p1, size / 4, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
todo_wine ok(ret, "Failed to split a placeholder.\n");
if (ret)
{
check_region_size(p, size / 2);
check_region_size(p1, size / 4);
}
ok(ret, "Failed to split a placeholder.\n");
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);
todo_wine ok(ret, "Failed to release a region.\n");
ok(ret, "Failed to release a region.\n");
ret = VirtualFree(p2, 0, MEM_RELEASE);
todo_wine ok(ret, "Failed to release a region.\n");
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);
......@@ -239,14 +236,13 @@ static void test_VirtualAlloc2(void)
p1 = p;
p2 = p + size / 2;
ret = VirtualFree(p1, size / 2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
todo_wine ok(ret, "Failed to split a placeholder.\n");
if (ret)
check_region_size(p1, size / 2);
ok(ret, "Failed to split a placeholder.\n");
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);
todo_wine ok(ret, "Failed to release a region.\n");
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);
......@@ -255,14 +251,13 @@ static void test_VirtualAlloc2(void)
p1 = p;
p2 = p + size;
ret = VirtualFree(p2, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
todo_wine ok(ret, "Failed to split a placeholder.\n");
if (ret)
check_region_size(p1, size);
ok(ret, "Failed to split a placeholder.\n");
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);
todo_wine ok(ret, "Failed to release a region.\n");
ok(ret, "Failed to release a region.\n");
}
static void test_VirtualAllocFromApp(void)
......
......@@ -354,13 +354,10 @@ static void test_NtAllocateVirtualMemoryEx(void)
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(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
if (status == STATUS_SUCCESS)
{
check_region_size(p, size / 2);
check_region_size(p1, size / 4);
}
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);
......@@ -381,11 +378,10 @@ static void test_NtAllocateVirtualMemoryEx(void)
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(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(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);
......@@ -404,10 +400,9 @@ static void test_NtAllocateVirtualMemoryEx(void)
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(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(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);
......
......@@ -2189,17 +2189,40 @@ static NTSTATUS decommit_pages( struct file_view *view, size_t start, size_t siz
/***********************************************************************
* view_make_placeholder
*
* Setup placeholder view.
* virtual_mutex must be held by caller.
*/
static void view_make_placeholder( struct file_view *view )
{
view->protect = VPROT_PLACEHOLDER | VPROT_FREE_PLACEHOLDER;
set_page_vprot( view->base, view->size, 0 );
anon_mmap_fixed( view->base, view->size, PROT_NONE, 0 );
}
/***********************************************************************
* free_pages
*
* Free some pages of a given view.
* virtual_mutex must be held by caller.
*/
static NTSTATUS free_pages( struct file_view *view, char *base, size_t size )
static NTSTATUS free_pages( struct file_view *view, char *base, size_t size, BOOL preserve_placeholder )
{
if (preserve_placeholder)
{
if (!size) return STATUS_INVALID_PARAMETER_3;
if (!(view->protect & VPROT_PLACEHOLDER)) return STATUS_CONFLICTING_ADDRESSES;
if (view->protect & VPROT_FREE_PLACEHOLDER && size == view->size) return STATUS_CONFLICTING_ADDRESSES;
}
else if (!size) size = view->size;
if (size == view->size)
{
assert( base == view->base );
delete_view( view );
if (preserve_placeholder) view_make_placeholder( view );
else delete_view( view );
return STATUS_SUCCESS;
}
if (view->base != base && base + size != (char *)view->base + view->size)
......@@ -2237,6 +2260,20 @@ static NTSTATUS free_pages( struct file_view *view, char *base, size_t size )
VIRTUAL_DEBUG_DUMP_VIEW( view );
}
if (preserve_placeholder)
{
if (!(view = alloc_view()))
{
ERR( "Out of memory for %p-%p\n", base, base + size );
return STATUS_NO_MEMORY;
}
view->base = base;
view->size = size;
view_make_placeholder( view );
register_view( view );
return STATUS_SUCCESS;
}
set_page_vprot( base, size, 0 );
if (arm64ec_map) clear_arm64ec_range( base, size );
unmap_area( base, size );
......@@ -4395,10 +4432,10 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
else if (!size && base != view->base) status = STATUS_FREE_VM_NOT_AT_BASE;
else if ((char *)view->base + view->size - base < size) status = STATUS_UNABLE_TO_FREE_VM;
else if (type == MEM_DECOMMIT) status = decommit_pages( view, base - (char *)view->base, size );
else if (type == MEM_RELEASE)
else if (type == MEM_RELEASE || (type == (MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER)))
{
status = free_pages( view, base, size, type & MEM_PRESERVE_PLACEHOLDER );
if (!size) size = view->size;
status = free_pages( view, base, size );
}
else status = STATUS_INVALID_PARAMETER;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment