Commit 03096546 authored by Paul Gofman's avatar Paul Gofman Committed by Alexandre Julliard

ntdll: Support MEM_COALESCE_PLACEHOLDERS in NtFreeVirtualMemory().

parent d5f23441
...@@ -295,9 +295,9 @@ static void test_NtAllocateVirtualMemoryEx(void) ...@@ -295,9 +295,9 @@ static void test_NtAllocateVirtualMemoryEx(void)
{ {
MEMORY_BASIC_INFORMATION mbi; MEMORY_BASIC_INFORMATION mbi;
MEM_EXTENDED_PARAMETER ext[2]; MEM_EXTENDED_PARAMETER ext[2];
char *p, *p1, *p2, *p3;
void *addresses[16]; void *addresses[16];
SIZE_T size, size2; SIZE_T size, size2;
char *p, *p1, *p2;
ULONG granularity; ULONG granularity;
NTSTATUS status; NTSTATUS status;
ULONG_PTR count; ULONG_PTR count;
...@@ -510,6 +510,7 @@ static void test_NtAllocateVirtualMemoryEx(void) ...@@ -510,6 +510,7 @@ static void test_NtAllocateVirtualMemoryEx(void)
p1 = addr1; p1 = addr1;
p2 = p1 + size / 4; p2 = p1 + size / 4;
p3 = p2 + size / 4;
size2 = size / 4; size2 = size / 4;
status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
...@@ -517,12 +518,79 @@ static void test_NtAllocateVirtualMemoryEx(void) ...@@ -517,12 +518,79 @@ static void test_NtAllocateVirtualMemoryEx(void)
ok(size2 == 0x4000, "Unexpected size %#Ix.\n", size2); ok(size2 == 0x4000, "Unexpected size %#Ix.\n", size2);
ok(p1 == addr1, "Unexpected addr %p, expected %p.\n", p1, addr1); ok(p1 == addr1, "Unexpected addr %p, expected %p.\n", p1, addr1);
status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
check_region_size(p1, p2 - p1);
check_region_size(p2, p3 - p2);
check_region_size(p3, size - (p3 - p1));
status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS);
ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status);
status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size, MEM_COALESCE_PLACEHOLDERS);
ok(status == STATUS_INVALID_PARAMETER_4, "Unexpected status %08lx.\n", status);
size2 = size + 0x1000;
status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS);
ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status);
size2 = size - 0x1000;
status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS);
ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status);
p1 = (char *)addr1 + 0x1000;
status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS);
ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status);
p1 = addr1;
size2 = 0;
status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS);
ok(status == STATUS_INVALID_PARAMETER_3, "Unexpected status %08lx.\n", status);
status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size, MEM_RELEASE);
ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status);
status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS);
ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
ok(size == 0x10000, "Unexpected size %#Ix.\n", size);
ok(p1 == addr1, "Unexpected addr %p, expected %p.\n", p1, addr1);
check_region_size(p1, size);
size2 = size / 4;
status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
ok(size2 == 0x4000, "Unexpected size %#Ix.\n", size2);
ok(p1 == addr1, "Unexpected addr %p, expected %p.\n", p1, addr1);
check_region_size(p1, size / 4); check_region_size(p1, size / 4);
check_region_size(p2, size - size / 4); check_region_size(p2, size - size / 4);
status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE);
size2 = size - size / 4;
status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), (void **)&p2, &size2, MEM_RESERVE | MEM_REPLACE_PLACEHOLDER,
PAGE_READWRITE, NULL, 0);
ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS);
ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status);
size2 = size - size / 4;
status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE); status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE);
ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
ok(size2 == 0xc000, "Unexpected size %#Ix.\n", size2);
ok(p2 == p1 + size / 4, "Unexpected addr %p, expected %p.\n", p2, p1 + size / 4);
status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS);
ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status);
size2 = size / 4;
status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE);
ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
ok(size2 == 0x4000, "Unexpected size %#Ix.\n", size2);
ok(p1 == addr1, "Unexpected addr %p, expected %p.\n", p1, addr1);
size2 = 0;
status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p3, &size2, MEM_RELEASE);
ok(status == STATUS_MEMORY_NOT_ALLOCATED, "Unexpected status %08lx.\n", status);
/* Split in two regions, specifying second half. */ /* Split in two regions, specifying second half. */
addr1 = NULL; addr1 = NULL;
......
...@@ -2295,6 +2295,53 @@ static NTSTATUS free_pages( struct file_view *view, char *base, size_t size ) ...@@ -2295,6 +2295,53 @@ static NTSTATUS free_pages( struct file_view *view, char *base, size_t size )
/*********************************************************************** /***********************************************************************
* coalesce_placeholders
*
* Coalesce placeholder views.
* virtual_mutex must be held by caller.
*/
static NTSTATUS coalesce_placeholders( struct file_view *view, char *base, size_t size )
{
struct rb_entry *next;
struct file_view *curr_view, *next_view;
unsigned int i, view_count = 0;
size_t views_size = 0;
if (!size) return STATUS_INVALID_PARAMETER_3;
if (base != view->base) return STATUS_CONFLICTING_ADDRESSES;
curr_view = view;
while (curr_view->protect & VPROT_FREE_PLACEHOLDER)
{
++view_count;
views_size += curr_view->size;
if (views_size >= size) break;
if (!(next = rb_next( &curr_view->entry ))) break;
next_view = RB_ENTRY_VALUE( next, struct file_view, entry );
if ((char *)curr_view->base + curr_view->size != next_view->base) break;
curr_view = next_view;
}
if (view_count < 2 || size != views_size) return STATUS_CONFLICTING_ADDRESSES;
for (i = 1; i < view_count; ++i)
{
curr_view = RB_ENTRY_VALUE( rb_next( &view->entry ), struct file_view, entry );
unregister_view( curr_view );
free_view( curr_view );
}
unregister_view( view );
view->size = views_size;
register_view( view );
VIRTUAL_DEBUG_DUMP_VIEW( view );
return STATUS_SUCCESS;
}
/***********************************************************************
* allocate_dos_memory * allocate_dos_memory
* *
* Allocate the DOS memory range. * Allocate the DOS memory range.
...@@ -4445,7 +4492,8 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si ...@@ -4445,7 +4492,8 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
else if (!(view = find_view( base, 0 ))) status = STATUS_MEMORY_NOT_ALLOCATED; else if (!(view = find_view( base, 0 ))) status = STATUS_MEMORY_NOT_ALLOCATED;
else if (!is_view_valloc( view )) status = STATUS_INVALID_PARAMETER; else if (!is_view_valloc( view )) status = STATUS_INVALID_PARAMETER;
else if (!size && base != view->base) status = STATUS_FREE_VM_NOT_AT_BASE; 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 ((char *)view->base + view->size - base < size && !(type & MEM_COALESCE_PLACEHOLDERS))
status = STATUS_UNABLE_TO_FREE_VM;
else switch (type) else switch (type)
{ {
case MEM_DECOMMIT: case MEM_DECOMMIT:
...@@ -4458,6 +4506,12 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si ...@@ -4458,6 +4506,12 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
case MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER: case MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER:
status = free_pages_preserve_placeholder( view, base, size ); status = free_pages_preserve_placeholder( view, base, size );
break; break;
case MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS:
status = coalesce_placeholders( view, base, size );
break;
case MEM_COALESCE_PLACEHOLDERS:
status = STATUS_INVALID_PARAMETER_4;
break;
default: default:
status = STATUS_INVALID_PARAMETER; status = STATUS_INVALID_PARAMETER;
break; break;
......
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