The partial free is not supported from VirtualFree (we have a test for that) but NtFreeVirtualMemory supports it.
The primary motivation behind these patches is the preparation for VM placeholders support. With those flags (MEM_RESERVE_PLACEHOLDER, MEM_PRESERVE_PLACEHOLDER, MEM_REPLACE_PLACEHOLDER and MEM_COALESCE_PLACEHOLDERS) views might be arbitrary split or joined with just page alignment.
-- v2: ntdll: Add logging for free ranges. ntdll: Support partial view release in NtFreeVirtualMemory(). ntdll: Factor out some view manipulation functions. ntdll: Fully support unaligned views in free ranges management. ntdll: Fix size validation in NtFreeVirtualMemory(). kernelbase: Validate nonzero size for MEM_RELEASE in VirtualFreeEx(). ntdll/tests: Add tests for freeing a part of view.
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/virtual.c | 70 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index a239a75ad47..ec029d75f3d 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -1665,21 +1665,85 @@ static void test_syscalls(void)
static void test_NtFreeVirtualMemory(void) { + void *addr1, *addr; NTSTATUS status; - void *addr1; SIZE_T size;
size = 0x10000; addr1 = NULL; - status = NtAllocateVirtualMemory(NtCurrentProcess(), &addr1, 0, &size, MEM_RESERVE, PAGE_READWRITE); + status = NtAllocateVirtualMemory(NtCurrentProcess(), &addr1, 0, &size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
size = 0; status = NtFreeVirtualMemory(NULL, &addr1, &size, MEM_RELEASE); ok(status == STATUS_INVALID_HANDLE, "Unexpected status %08lx.\n", status);
+ addr = (char *)addr1 + 0x1000; + size = 0; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); + ok(status == STATUS_FREE_VM_NOT_AT_BASE, "Unexpected status %08lx.\n", status); + + size = 0x11000; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_RELEASE); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + todo_wine ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); + + addr = (char *)addr1 + 0x1001; + size = 0xffff; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); + todo_wine ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); + ok(size == 0xffff, "Unexpected size %p.\n", (void *)size); + ok(addr == (char *)addr1 + 0x1001, "Got addr %p, addr1 %p.\n", addr, addr1); + + size = 0xfff; + addr = (char *)addr1 + 0x1001; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); + todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + *(volatile char *)addr1 = 1; + *((volatile char *)addr1 + 0x2000) = 1; + todo_wine ok(size == 0x1000, "Unexpected size %p.\n", (void *)size); + todo_wine ok(addr == (char *)addr1 + 0x1000, "Got addr %p, addr1 %p.\n", addr, addr1); + + size = 0xfff; + addr = (char *)addr1 + 1; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); + todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + *((volatile char *)addr1 + 0x2000) = 1; + todo_wine ok(size == 0x1000, "Unexpected size %p.\n", (void *)size); + todo_wine ok(addr == addr1, "Got addr %p, addr1 %p.\n", addr, addr1); + + size = 0x1000; + addr = addr1; + status = NtAllocateVirtualMemory(NtCurrentProcess(), &addr, 0, &size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(addr == addr1, "Unexpected addr %p, addr1 %p.\n", addr, addr1); + ok(size == 0x1000, "Unexpected size %p.\n", (void *)size); + + size = 0x10000; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_DECOMMIT); + todo_wine ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); + + size = 0x10000; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_RELEASE); + todo_wine ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); + + size = 0; + addr = (char *)addr1 + 0x1000; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); + todo_wine ok(status == STATUS_MEMORY_NOT_ALLOCATED, "Unexpected status %08lx.\n", status); + + size = 0x1000; + addr = (char *)addr1 + 0x1000; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_DECOMMIT); + todo_wine ok(status == STATUS_MEMORY_NOT_ALLOCATED, "Unexpected status %08lx.\n", status); + + size = 0; + addr = (char *)addr1 + 0x2000; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); + todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + + size = 0x1000; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_RELEASE); + todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); }
static void test_prefetch(void)
From: Paul Gofman pgofman@codeweavers.com
--- dlls/kernelbase/memory.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c index c4a484b5a30..4188eebf181 100644 --- a/dlls/kernelbase/memory.c +++ b/dlls/kernelbase/memory.c @@ -457,6 +457,12 @@ BOOL WINAPI DECLSPEC_HOTPATCH VirtualFree( void *addr, SIZE_T size, DWORD type ) */ BOOL WINAPI DECLSPEC_HOTPATCH VirtualFreeEx( HANDLE process, void *addr, SIZE_T size, DWORD type ) { + if (type == MEM_RELEASE && size) + { + WARN( "Trying to release memory with specified size.\n" ); + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } return set_ntstatus( NtFreeVirtualMemory( process, &addr, &size, type )); }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/virtual.c | 16 ++++++++-------- dlls/ntdll/unix/virtual.c | 26 ++++++++++++++++++-------- 2 files changed, 26 insertions(+), 16 deletions(-)
diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index ec029d75f3d..823c947a550 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -1685,12 +1685,12 @@ static void test_NtFreeVirtualMemory(void)
size = 0x11000; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_RELEASE); - todo_wine ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); + ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status);
addr = (char *)addr1 + 0x1001; size = 0xffff; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); - todo_wine ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); + ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); ok(size == 0xffff, "Unexpected size %p.\n", (void *)size); ok(addr == (char *)addr1 + 0x1001, "Got addr %p, addr1 %p.\n", addr, addr1);
@@ -1700,16 +1700,16 @@ static void test_NtFreeVirtualMemory(void) todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); *(volatile char *)addr1 = 1; *((volatile char *)addr1 + 0x2000) = 1; - todo_wine ok(size == 0x1000, "Unexpected size %p.\n", (void *)size); - todo_wine ok(addr == (char *)addr1 + 0x1000, "Got addr %p, addr1 %p.\n", addr, addr1); + ok(size == 0x1000, "Unexpected size %p.\n", (void *)size); + ok(addr == (char *)addr1 + 0x1000, "Got addr %p, addr1 %p.\n", addr, addr1);
size = 0xfff; addr = (char *)addr1 + 1; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); *((volatile char *)addr1 + 0x2000) = 1; - todo_wine ok(size == 0x1000, "Unexpected size %p.\n", (void *)size); - todo_wine ok(addr == addr1, "Got addr %p, addr1 %p.\n", addr, addr1); + ok(size == 0x1000, "Unexpected size %p.\n", (void *)size); + ok(addr == addr1, "Got addr %p, addr1 %p.\n", addr, addr1);
size = 0x1000; addr = addr1; @@ -1729,12 +1729,12 @@ static void test_NtFreeVirtualMemory(void) size = 0; addr = (char *)addr1 + 0x1000; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); - todo_wine ok(status == STATUS_MEMORY_NOT_ALLOCATED, "Unexpected status %08lx.\n", status); + ok(status == STATUS_MEMORY_NOT_ALLOCATED, "Unexpected status %08lx.\n", status);
size = 0x1000; addr = (char *)addr1 + 0x1000; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_DECOMMIT); - todo_wine ok(status == STATUS_MEMORY_NOT_ALLOCATED, "Unexpected status %08lx.\n", status); + ok(status == STATUS_MEMORY_NOT_ALLOCATED, "Unexpected status %08lx.\n", status);
size = 0; addr = (char *)addr1 + 0x2000; diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 7769d2c31f5..65bca69103b 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -4015,26 +4015,36 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si if (addr == (void *)1 && !size && type == MEM_RELEASE) virtual_release_address_space(); else status = STATUS_INVALID_PARAMETER; } - else if (!(view = find_view( base, size )) || !is_view_valloc( view )) - { - status = STATUS_INVALID_PARAMETER; - } + else if (!(view = find_view( base, 0 ))) status = STATUS_MEMORY_NOT_ALLOCATED; + else if (!is_view_valloc( view )) status = STATUS_INVALID_PARAMETER; else if (type == MEM_RELEASE) { /* Free the pages */
- if (size) status = STATUS_INVALID_PARAMETER; - else if (base != view->base) status = STATUS_FREE_VM_NOT_AT_BASE; + if (size && (char *)view->base + view->size - base < size) status = STATUS_UNABLE_TO_FREE_VM; + else if (!size && base != view->base) status = STATUS_FREE_VM_NOT_AT_BASE; else { + if (!size) size = view->size; + + if (size == view->size) + { + assert( base == view->base ); + delete_view( view ); + } + else + { + FIXME( "Parial view release is not supported.\n" ); + status = STATUS_INVALID_PARAMETER; + } *addr_ptr = base; - *size_ptr = view->size; - delete_view( view ); + *size_ptr = size; } } else if (type == MEM_DECOMMIT) { if (!size && base != view->base) status = STATUS_FREE_VM_NOT_AT_BASE; + else if (base - (char *)view->base + size > view->size) status = STATUS_UNABLE_TO_FREE_VM; else status = decommit_pages( view, base - (char *)view->base, size ); if (status == STATUS_SUCCESS) {
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/unix/virtual.c | 40 ++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 65bca69103b..62f294e5070 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -726,17 +726,19 @@ static void free_ranges_insert_view( struct file_view *view ) assert( range != free_ranges_end ); assert( range->end > view_base || next != free_ranges_end );
- /* this happens because AT_ROUND_TO_PAGE was used with NtMapViewOfSection to force 4kB aligned mapping. */ - if ((range->end > view_base && range->base >= view_end) || - (range->end == view_base && next->base >= view_end)) - { - /* on Win64, assert that it's correctly aligned so we're not going to be in trouble later */ -#ifdef _WIN64 - assert( view->base == view_base ); -#endif - WARN( "range %p - %p is already mapped\n", view_base, view_end ); + /* Free ranges addresses are aligned at granularity_mask while the views may be not. */ + + if (range->base > view_base) + view_base = range->base; + if (range->end < view_end) + view_end = range->end; + if (range->end == view_base && next->base >= view_end) + view_end = view_base; + + TRACE( "%p - %p, aligned %p - %p.\n", view->base, (char *)view->base + view->size, view_base, view_end ); + + if (view_end <= view_base) return; - }
/* this should never happen */ if (range->base > view_base || range->end < view_end) @@ -786,9 +788,7 @@ static void free_ranges_remove_view( struct file_view *view ) struct range_entry *range = free_ranges_lower_bound( view_base ); struct range_entry *next = range + 1;
- /* It's possible to use AT_ROUND_TO_PAGE on 32bit with NtMapViewOfSection to force 4kB alignment, - * and this breaks our assumptions. Look at the views around to check if the range is still in use. */ -#ifndef _WIN64 + /* Free ranges addresses are aligned at granularity_mask while the views may be not. */ struct file_view *prev_view = RB_ENTRY_VALUE( rb_prev( &view->entry ), struct file_view, entry ); struct file_view *next_view = RB_ENTRY_VALUE( rb_next( &view->entry ), struct file_view, entry ); void *prev_view_base = prev_view ? ROUND_ADDR( prev_view->base, granularity_mask ) : NULL; @@ -796,13 +796,15 @@ static void free_ranges_remove_view( struct file_view *view ) void *next_view_base = next_view ? ROUND_ADDR( next_view->base, granularity_mask ) : NULL; void *next_view_end = next_view ? ROUND_ADDR( (char *)next_view->base + next_view->size + granularity_mask, granularity_mask ) : NULL;
- if ((prev_view_base < view_end && prev_view_end > view_base) || - (next_view_base < view_end && next_view_end > view_base)) - { - WARN( "range %p - %p is still mapped\n", view_base, view_end ); + if (prev_view_end && prev_view_end > view_base && prev_view_base < view_end) + view_base = prev_view_end; + if (next_view_base && next_view_base < view_end && next_view_end > view_base) + view_end = next_view_base; + + TRACE( "%p - %p, aligned %p - %p.\n", view->base, (char *)view->base + view->size, view_base, view_end ); + + if (view_end <= view_base) return; - } -#endif
/* free_ranges initial value is such that the view is either inside range or before another one. */ assert( range != free_ranges_end );
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/unix/virtual.c | 47 +++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 7 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 62f294e5070..506b8f0d72b 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -1519,6 +1519,31 @@ static struct file_view *alloc_view(void) }
+/*********************************************************************** + * free_view + * + * Free memory for view structure. virtual_mutex must be held by caller. + */ +static void free_view( struct file_view *view ) +{ + *(struct file_view **)view = next_free_view; + next_free_view = view; +} + + +/*********************************************************************** + * unregister_view + * + * Remove view from the tree and update free ranges. virtual_mutex must be held by caller. + */ +static void unregister_view( struct file_view *view ) +{ + if (mmap_is_in_reserved_area( view->base, view->size )) + free_ranges_remove_view( view ); + wine_rb_remove( &views_tree, &view->entry ); +} + + /*********************************************************************** * delete_view * @@ -1528,11 +1553,21 @@ static void delete_view( struct file_view *view ) /* [in] View */ { if (!(view->protect & VPROT_SYSTEM)) unmap_area( view->base, view->size ); set_page_vprot( view->base, view->size, 0 ); + unregister_view( view ); + free_view( view ); +} + + +/*********************************************************************** + * register_view + * + * Add view to the tree and update free ranges. virtual_mutex must be held by caller. + */ +static void register_view( struct file_view *view ) +{ + wine_rb_put( &views_tree, view->base, &view->entry ); if (mmap_is_in_reserved_area( view->base, view->size )) - free_ranges_remove_view( view ); - wine_rb_remove( &views_tree, &view->entry ); - *(struct file_view **)view = next_free_view; - next_free_view = view; + free_ranges_insert_view( view ); }
@@ -1576,9 +1611,7 @@ static NTSTATUS create_view( struct file_view **view_ret, void *base, size_t siz view->protect = vprot; set_page_vprot( base, size, vprot );
- wine_rb_put( &views_tree, view->base, &view->entry ); - if (mmap_is_in_reserved_area( view->base, view->size )) - free_ranges_insert_view( view ); + register_view( view );
*view_ret = view;
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/virtual.c | 14 ++++++------- dlls/ntdll/unix/virtual.c | 42 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 9 deletions(-)
diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index 823c947a550..79b067ae640 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -1697,7 +1697,7 @@ static void test_NtFreeVirtualMemory(void) size = 0xfff; addr = (char *)addr1 + 0x1001; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); - todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); *(volatile char *)addr1 = 1; *((volatile char *)addr1 + 0x2000) = 1; ok(size == 0x1000, "Unexpected size %p.\n", (void *)size); @@ -1706,7 +1706,7 @@ static void test_NtFreeVirtualMemory(void) size = 0xfff; addr = (char *)addr1 + 1; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); - todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); *((volatile char *)addr1 + 0x2000) = 1; ok(size == 0x1000, "Unexpected size %p.\n", (void *)size); ok(addr == addr1, "Got addr %p, addr1 %p.\n", addr, addr1); @@ -1714,17 +1714,17 @@ static void test_NtFreeVirtualMemory(void) size = 0x1000; addr = addr1; status = NtAllocateVirtualMemory(NtCurrentProcess(), &addr, 0, &size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); ok(addr == addr1, "Unexpected addr %p, addr1 %p.\n", addr, addr1); ok(size == 0x1000, "Unexpected size %p.\n", (void *)size);
size = 0x10000; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_DECOMMIT); - todo_wine ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); + ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status);
size = 0x10000; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_RELEASE); - todo_wine ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); + ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status);
size = 0; addr = (char *)addr1 + 0x1000; @@ -1739,11 +1739,11 @@ static void test_NtFreeVirtualMemory(void) size = 0; addr = (char *)addr1 + 0x2000; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); - todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
size = 0x1000; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_RELEASE); - todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); }
static void test_prefetch(void) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 506b8f0d72b..566e2dcfb90 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -4069,8 +4069,46 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si } else { - FIXME( "Parial view release is not supported.\n" ); - status = STATUS_INVALID_PARAMETER; + struct file_view *new_view = NULL; + + if (view->base != base && base + size != (char *)view->base + view->size + && !(new_view = alloc_view())) + { + ERR( "out of memory for %p-%p\n", base, (char *)base + size ); + return STATUS_NO_MEMORY; + } + unregister_view( view ); + + if (new_view) + { + new_view->base = base + size; + new_view->size = (char *)view->base + view->size - (char *)new_view->base; + new_view->protect = view->protect; + + view->size = base - (char *)view->base; + register_view( view ); + register_view( new_view ); + + VIRTUAL_DEBUG_DUMP_VIEW( view ); + VIRTUAL_DEBUG_DUMP_VIEW( new_view ); + } + else + { + if (view->base == base) + { + view->base = base + size; + view->size -= size; + } + else + { + view->size = base - (char *)view->base; + } + register_view( view ); + VIRTUAL_DEBUG_DUMP_VIEW( view ); + } + + set_page_vprot( base, size, 0 ); + unmap_area( base, size ); } *addr_ptr = base; *size_ptr = size;
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/unix/virtual.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 566e2dcfb90..0dc11178206 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -77,6 +77,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(virtual); WINE_DECLARE_DEBUG_CHANNEL(module); +WINE_DECLARE_DEBUG_CHANNEL(virtual_ranges);
struct preload_info { @@ -187,6 +188,7 @@ static struct list teb_list = LIST_INIT( teb_list ); #define ROUND_SIZE(addr,size) (((SIZE_T)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask)
#define VIRTUAL_DEBUG_DUMP_VIEW(view) do { if (TRACE_ON(virtual)) dump_view(view); } while (0) +#define VIRTUAL_DEBUG_DUMP_RANGES() do { if (TRACE_ON(virtual_ranges)) dump_free_ranges(); } while (0)
#ifndef MAP_NORESERVE #define MAP_NORESERVE 0 @@ -709,6 +711,12 @@ static struct range_entry *free_ranges_lower_bound( void *addr ) return begin; }
+static void dump_free_ranges(void) +{ + struct range_entry *r; + for (r = free_ranges; r != free_ranges_end; ++r) + TRACE_(virtual_ranges)("%p - %p.\n", r->base, r->end); +}
/*********************************************************************** * free_ranges_insert_view @@ -738,7 +746,10 @@ static void free_ranges_insert_view( struct file_view *view ) TRACE( "%p - %p, aligned %p - %p.\n", view->base, (char *)view->base + view->size, view_base, view_end );
if (view_end <= view_base) + { + VIRTUAL_DEBUG_DUMP_RANGES(); return; + }
/* this should never happen */ if (range->base > view_base || range->end < view_end) @@ -766,16 +777,19 @@ static void free_ranges_insert_view( struct file_view *view ) else range->base = view_end;
- if (range->base < range->end) return; - + if (range->base < range->end) + { + VIRTUAL_DEBUG_DUMP_RANGES(); + return; + } /* and possibly remove it if it's now empty */ memmove( range, next, (free_ranges_end - next) * sizeof(struct range_entry) ); free_ranges_end -= 1; assert( free_ranges_end - free_ranges > 0 ); } + VIRTUAL_DEBUG_DUMP_RANGES(); }
- /*********************************************************************** * free_ranges_remove_view * @@ -804,8 +818,10 @@ static void free_ranges_remove_view( struct file_view *view ) TRACE( "%p - %p, aligned %p - %p.\n", view->base, (char *)view->base + view->size, view_base, view_end );
if (view_end <= view_base) + { + VIRTUAL_DEBUG_DUMP_RANGES(); return; - + } /* free_ranges initial value is such that the view is either inside range or before another one. */ assert( range != free_ranges_end ); assert( range->end > view_base || next != free_ranges_end ); @@ -847,6 +863,7 @@ static void free_ranges_remove_view( struct file_view *view ) range->base = view_base; range->end = view_end; } + VIRTUAL_DEBUG_DUMP_RANGES(); }