Added ntdll-Placeholders patchset.

This commit is contained in:
Paul Gofman 2022-11-12 18:23:09 -06:00 committed by Alistair Leslie-Hughes
parent 2e9f238732
commit 1a2b47b084
19 changed files with 1837 additions and 0 deletions

View File

@ -0,0 +1,105 @@
From 7c13335d926a1b47f7cf88065d641c4d5fa80a59 Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Fri, 11 Nov 2022 17:51:26 -0600
Subject: [PATCH] ntdll/tests: Add tests for freeing a part of view.
---
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 6831fe3c522..8e94566fb7f 100644
--- a/dlls/ntdll/tests/virtual.c
+++ b/dlls/ntdll/tests/virtual.c
@@ -1639,21 +1639,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)
--
2.38.1

View File

@ -0,0 +1,30 @@
From bc937422e5f600be650e21de5f6c9b8656d5c23c Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Fri, 11 Nov 2022 17:56:42 -0600
Subject: [PATCH] kernelbase: Validate nonzero size for MEM_RELEASE in
VirtualFreeEx().
---
dlls/kernelbase/memory.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c
index 2a503587e93..c01fe817972 100644
--- a/dlls/kernelbase/memory.c
+++ b/dlls/kernelbase/memory.c
@@ -447,6 +447,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 ));
}
--
2.38.1

View File

@ -0,0 +1,117 @@
From 22dc17764c3b231ebd226e479686a00c7aaaf01a Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Fri, 11 Nov 2022 18:12:47 -0600
Subject: [PATCH] ntdll: Fix size validation in NtFreeVirtualMemory().
---
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 8e94566fb7f..81e9bd0bda3 100644
--- a/dlls/ntdll/tests/virtual.c
+++ b/dlls/ntdll/tests/virtual.c
@@ -1659,12 +1659,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);
@@ -1674,16 +1674,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;
@@ -1703,12 +1703,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 24d5a4e2da8..4cb0f349ffc 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -4127,26 +4127,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)
{
--
2.38.1

View File

@ -0,0 +1,81 @@
From c97697f6bbc3c9671210e480f2fcfe761b54893d Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Fri, 11 Nov 2022 18:30:20 -0600
Subject: [PATCH] ntdll: Fully support unaligned views in free ranges
management.
---
dlls/ntdll/unix/virtual.c | 41 ++++++++++++++++++++-------------------
1 file changed, 21 insertions(+), 20 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 4cb0f349ffc..2dca5dfa45f 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -749,18 +749,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 virtual_alloc_thread_stack shrinks a view, then creates another one on top,
- * or 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)
@@ -810,9 +811,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;
@@ -820,13 +819,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 );
--
2.38.1

View File

@ -0,0 +1,85 @@
From 4baf5566da8495ef3b260783ed88f175e43b4f70 Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Fri, 11 Nov 2022 18:37:43 -0600
Subject: [PATCH] ntdll: Factor out some view manipulation functions.
---
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 2dca5dfa45f..bdc410472ec 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -1563,6 +1563,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
*
@@ -1572,11 +1597,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 );
}
@@ -1620,9 +1655,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;
--
2.38.1

View File

@ -0,0 +1,123 @@
From 261ba5e0003f13c83f9f08e5b3931862586f46d3 Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Fri, 11 Nov 2022 18:41:50 -0600
Subject: [PATCH] ntdll: Support partial view release in NtFreeVirtualMemory().
---
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 81e9bd0bda3..0dccb35bd27 100644
--- a/dlls/ntdll/tests/virtual.c
+++ b/dlls/ntdll/tests/virtual.c
@@ -1671,7 +1671,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);
@@ -1680,7 +1680,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);
@@ -1688,17 +1688,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;
@@ -1713,11 +1713,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 bdc410472ec..5775287cd19 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -4180,8 +4180,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;
--
2.38.1

View File

@ -0,0 +1,99 @@
From aa5b49a7893ddb97b11251c65506d242e2e160f9 Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Tue, 4 Oct 2022 20:26:39 -0500
Subject: [PATCH] ntdll: Add logging for free ranges.
---
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 5775287cd19..7142d2adf79 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -76,6 +76,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(virtual);
WINE_DECLARE_DEBUG_CHANNEL(module);
+WINE_DECLARE_DEBUG_CHANNEL(virtual_ranges);
struct preload_info
{
@@ -186,6 +187,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
@@ -732,6 +734,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
@@ -761,7 +769,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)
@@ -789,16 +800,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
*
@@ -827,8 +841,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 );
@@ -870,6 +886,7 @@ static void free_ranges_remove_view( struct file_view *view )
range->base = view_base;
range->end = view_end;
}
+ VIRTUAL_DEBUG_DUMP_RANGES();
}
--
2.38.1

View File

@ -0,0 +1,58 @@
From 72dcf52735e6306fa67f25f49fd78da24d7d89cb Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Thu, 10 Nov 2022 18:40:18 -0600
Subject: [PATCH] ntdll: Handle NULL process handle in MapViewOfFile3().
Based on a patch by Nikolay Sivov.
---
dlls/kernelbase/memory.c | 2 ++
dlls/ntdll/tests/virtual.c | 13 +++++++++++++
2 files changed, 15 insertions(+)
diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c
index c01fe817972..ee12f6abb91 100644
--- a/dlls/kernelbase/memory.c
+++ b/dlls/kernelbase/memory.c
@@ -255,6 +255,8 @@ LPVOID WINAPI DECLSPEC_HOTPATCH MapViewOfFile3( HANDLE handle, HANDLE process, P
LARGE_INTEGER off;
void *addr;
+ if (!process) process = GetCurrentProcess();
+
addr = baseaddr;
off.QuadPart = offset;
if (!set_ntstatus( NtMapViewOfSectionEx( handle, process, &addr, &off, &size, alloc_type, protection,
diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c
index 0dccb35bd27..486efabaf70 100644
--- a/dlls/ntdll/tests/virtual.c
+++ b/dlls/ntdll/tests/virtual.c
@@ -1060,6 +1060,13 @@ static void test_NtMapViewOfSection(void)
process = create_target_process("sleep");
ok(process != NULL, "Can't start process\n");
+ ptr = NULL;
+ size = 0;
+ offset.QuadPart = 0;
+ status = NtMapViewOfSection(mapping, NULL, &ptr, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE);
+ ok(status == STATUS_INVALID_HANDLE, "NtMapViewOfSection returned %08lx\n", status);
+ ok(!((ULONG_PTR)ptr & 0xffff), "returned memory %p is not aligned to 64k\n", ptr);
+
ptr = NULL;
size = 0;
offset.QuadPart = 0;
@@ -1303,6 +1310,12 @@ static void test_NtMapViewOfSectionEx(void)
process = create_target_process("sleep");
ok(process != NULL, "Can't start process\n");
+ ptr = NULL;
+ size = 0;
+ offset.QuadPart = 0;
+ status = pNtMapViewOfSectionEx(mapping, NULL, &ptr, &offset, &size, 0, PAGE_READWRITE, NULL, 0);
+ ok(status == STATUS_INVALID_HANDLE, "Unexpected status %08lx\n", status);
+
ptr = NULL;
size = 0;
offset.QuadPart = 0;
--
2.38.1

View File

@ -0,0 +1,119 @@
From 5275b219783f0a85e3fad17ac0f999c98d4b7b1c Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Thu, 10 Nov 2022 18:43:05 -0600
Subject: [PATCH] ntdll: Support MEM_PRESERVE_PLACEHOLDER in
NtFreeVirtualMemory().
Based on a patch by Nikolay Sivov.
---
dlls/ntdll/unix/virtual.c | 46 +++++++++++++++++++++++++++++++++------
1 file changed, 39 insertions(+), 7 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 7142d2adf79..85c4ab878b3 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -123,6 +123,7 @@ struct file_view
#define VPROT_WRITTEN 0x80
/* per-mapping protection flags */
#define VPROT_SYSTEM 0x0200 /* system view (underlying mmap not under our control) */
+#define VPROT_PLACEHOLDER 0x0400
/* Conversion from VPROT_* to Win32 flags */
static const BYTE VIRTUAL_Win32Flags[16] =
@@ -1115,6 +1116,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_PLACEHOLDER)
+ TRACE( " (placeholder)\n" );
else if (view->protect & SEC_IMAGE)
TRACE( " (image)\n" );
else if (view->protect & SEC_FILE)
@@ -4180,7 +4183,7 @@ 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 (!is_view_valloc( view )) status = STATUS_INVALID_PARAMETER;
- else if (type == MEM_RELEASE)
+ else if (type == MEM_RELEASE || (type == (MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER)))
{
/* Free the pages */
@@ -4190,14 +4193,15 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
{
if (!size) size = view->size;
- if (size == view->size)
+ if (type == MEM_RELEASE && size == view->size)
{
assert( base == view->base );
delete_view( view );
}
else
{
- struct file_view *new_view = NULL;
+ struct file_view *new_view = NULL, *preserve_view = NULL;
+ int preserve_whole;
if (view->base != base && base + size != (char *)view->base + view->size
&& !(new_view = alloc_view()))
@@ -4205,7 +4209,8 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
ERR( "out of memory for %p-%p\n", base, (char *)base + size );
return STATUS_NO_MEMORY;
}
- unregister_view( view );
+ preserve_whole = (size == view->size);
+ if (!preserve_whole) unregister_view( view );
if (new_view)
{
@@ -4220,7 +4225,7 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
VIRTUAL_DEBUG_DUMP_VIEW( view );
VIRTUAL_DEBUG_DUMP_VIEW( new_view );
}
- else
+ else if (!preserve_whole)
{
if (view->base == base)
{
@@ -4235,8 +4240,35 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
VIRTUAL_DEBUG_DUMP_VIEW( view );
}
- set_page_vprot( base, size, 0 );
- unmap_area( base, size );
+ if (type & MEM_PRESERVE_PLACEHOLDER)
+ {
+ if (preserve_whole)
+ {
+ view->protect = VPROT_PLACEHOLDER;
+ preserve_view = view;
+ }
+ else
+ {
+ if (!(preserve_view = alloc_view()))
+ {
+ ERR( "out of memory for %p-%p\n", base, (char *)base + size );
+ return STATUS_NO_MEMORY;
+ }
+ preserve_view->base = base;
+ preserve_view->size = size;
+ preserve_view->protect = VPROT_PLACEHOLDER;
+ register_view( preserve_view );
+ }
+ set_page_vprot( base, size, 0 );
+ if (anon_mmap_fixed(base, size, 0, 0) != base)
+ ERR("anon_mmap_fixed failed, err %s.\n", strerror(errno));
+ VIRTUAL_DEBUG_DUMP_VIEW( preserve_view );
+ }
+ else
+ {
+ set_page_vprot( base, size, 0 );
+ unmap_area( base, size );
+ }
}
*addr_ptr = base;
*size_ptr = size;
--
2.38.1

View File

@ -0,0 +1,46 @@
From 0a8dca419f3f5eacab2e9e11903cfc4c0a58dc93 Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Thu, 10 Nov 2022 18:48:14 -0600
Subject: [PATCH] ntdll: Pass allocation type to map_view().
Based on a patch by Nikolay Sivov.
---
dlls/ntdll/unix/virtual.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 85c4ab878b3..eb1d186e11c 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -2007,8 +2007,9 @@ static NTSTATUS map_fixed_area( void *base, size_t size, unsigned int vprot )
* virtual_mutex must be held by caller.
*/
static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size,
- int top_down, unsigned int vprot, ULONG_PTR limit, size_t align_mask )
+ unsigned int alloc_type, unsigned int vprot, ULONG_PTR limit, size_t align_mask )
{
+ int top_down = alloc_type & MEM_TOP_DOWN;
void *ptr;
NTSTATUS status;
@@ -2223,7 +2224,7 @@ static NTSTATUS allocate_dos_memory( struct file_view **view, unsigned int vprot
if (mmap_is_in_reserved_area( low_64k, dosmem_size - 0x10000 ) != 1)
{
addr = anon_mmap_tryfixed( low_64k, dosmem_size - 0x10000, unix_prot, 0 );
- if (addr == MAP_FAILED) return map_view( view, NULL, dosmem_size, FALSE, vprot, 0, 0 );
+ if (addr == MAP_FAILED) return map_view( view, NULL, dosmem_size, 0, vprot, 0, 0 );
}
/* now try to allocate the low 64K too */
@@ -3236,7 +3237,7 @@ NTSTATUS virtual_alloc_thread_stack( INITIAL_TEB *stack, ULONG_PTR zero_bits, SI
server_enter_uninterrupted_section( &virtual_mutex, &sigset );
- if ((status = map_view( &view, NULL, size + extra_size, FALSE,
+ if ((status = map_view( &view, NULL, size + extra_size, 0,
VPROT_READ | VPROT_WRITE | VPROT_COMMITTED, get_zero_bits_mask( zero_bits ), 0 ))
!= STATUS_SUCCESS)
goto done;
--
2.38.1

View File

@ -0,0 +1,97 @@
From 3bf6197ee235a2686b026cd3f544919d06d31743 Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Thu, 10 Nov 2022 18:53:10 -0600
Subject: [PATCH] ntdll: Support MEM_RESERVE_PLACEHOLDER in
NtAllocateVirtualMemoryEx().
Based on a patch by Nikolay Sivov.
---
dlls/ntdll/unix/virtual.c | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index eb1d186e11c..27de38f8dfd 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -3922,13 +3922,17 @@ 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", type);
return STATUS_INVALID_PARAMETER;
}
+ if (type & MEM_RESERVE_PLACEHOLDER && (protect != PAGE_NOACCESS))
+ {
+ WARN("Wrong protect %#x for placeholder.\n", protect);
+ return STATUS_INVALID_PARAMETER;
+ }
/* Reserve the memory */
server_enter_uninterrupted_section( &virtual_mutex, &sigset );
@@ -3939,6 +3943,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;
if (protect & PAGE_NOCACHE) vprot |= SEC_NOCACHE;
if (vprot & VPROT_WRITECOPY) status = STATUS_INVALID_PAGE_PROTECTION;
@@ -3958,6 +3963,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_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 )
@@ -3991,6 +3997,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, type, protect );
@@ -4002,6 +4009,12 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR z
if (!is_wow64 && zero_bits >= 32) return STATUS_INVALID_PARAMETER_3;
#endif
+ if (type & ~type_mask)
+ {
+ WARN("Called with wrong alloc type flags %08x.\n", type);
+ return STATUS_INVALID_PARAMETER;
+ }
+
if (process != NtCurrentProcess())
{
apc_call_t call;
@@ -4044,6 +4057,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;
@@ -4051,6 +4066,12 @@ NTSTATUS WINAPI NtAllocateVirtualMemoryEx( HANDLE process, PVOID *ret, SIZE_T *s
if (count && !parameters) return STATUS_INVALID_PARAMETER;
+ if (type & ~type_mask)
+ {
+ WARN("Called with wrong alloc type flags %08x.\n", type);
+ return STATUS_INVALID_PARAMETER;
+ }
+
if (count)
{
MEM_ADDRESS_REQUIREMENTS *r = NULL;
--
2.38.1

View File

@ -0,0 +1,107 @@
From ef6b2b0ec45bbbb34dc8ced866c0e4c442157aa5 Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Thu, 10 Nov 2022 18:58:26 -0600
Subject: [PATCH] ntdll: Support MEM_REPLACE_PLACEHOLDER in
NtAllocateVirtualMemoryEx().
---
dlls/ntdll/unix/virtual.c | 41 +++++++++++++++++++++++++++++++++++----
1 file changed, 37 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 27de38f8dfd..3019c3699be 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -124,6 +124,7 @@ struct file_view
/* per-mapping protection flags */
#define VPROT_SYSTEM 0x0200 /* system view (underlying mmap not under our control) */
#define VPROT_PLACEHOLDER 0x0400
+#define VPROT_FROMPLACEHOLDER 0x0800
/* Conversion from VPROT_* to Win32 flags */
static const BYTE VIRTUAL_Win32Flags[16] =
@@ -2013,6 +2014,31 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size,
void *ptr;
NTSTATUS status;
+ if (alloc_type & MEM_REPLACE_PLACEHOLDER)
+ {
+ if ((*view_ret = find_view( base, 0 )))
+ {
+ TRACE( "found view %p, size %p, protect %#x.\n",
+ (*view_ret)->base, (void *)(*view_ret)->size, (*view_ret)->protect );
+ if ((*view_ret)->base != base || (*view_ret)->size != size)
+ return STATUS_CONFLICTING_ADDRESSES;
+ if (!((*view_ret)->protect & VPROT_PLACEHOLDER))
+ {
+ TRACE("Wrong protect %#x for MEM_REPLACE_PLACEHOLDER.\n", (*view_ret)->protect);
+ return STATUS_INVALID_PARAMETER;
+ }
+ (*view_ret)->protect = vprot | VPROT_FROMPLACEHOLDER;
+
+ if (!set_vprot( *view_ret, base, size, vprot | VPROT_COMMITTED ))
+ ERR("set_protection failed.\n");
+ if (vprot & VPROT_WRITEWATCH)
+ reset_write_watches( base, size );
+ return STATUS_SUCCESS;
+ }
+ TRACE("MEM_REPLACE_PLACEHOLDER view not found.\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
if (base)
{
if (is_beyond_limit( base, size, address_space_limit ))
@@ -3898,7 +3924,7 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ
if (*ret)
{
- if (type & MEM_RESERVE) /* Round down to 64k boundary */
+ if (type & MEM_RESERVE && !(type & MEM_REPLACE_PLACEHOLDER)) /* Round down to 64k boundary */
base = ROUND_ADDR( *ret, granularity_mask );
else
base = ROUND_ADDR( *ret, page_mask );
@@ -3922,7 +3948,8 @@ 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)))
+ if (!(type & (MEM_COMMIT | MEM_RESERVE | MEM_RESET))
+ || (type & MEM_REPLACE_PLACEHOLDER && !(type & MEM_RESERVE)))
{
WARN("called with wrong alloc type flags (%08x) !\n", type);
return STATUS_INVALID_PARAMETER;
@@ -3948,7 +3975,7 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ
if (vprot & VPROT_WRITECOPY) status = STATUS_INVALID_PAGE_PROTECTION;
else if (is_dos_memory) status = allocate_dos_memory( &view, vprot );
- else status = map_view( &view, base, size, type & MEM_TOP_DOWN, vprot, limit,
+ else status = map_view( &view, base, size, type & (MEM_TOP_DOWN | MEM_REPLACE_PLACEHOLDER), vprot, limit,
align ? align - 1 : granularity_mask );
if (status == STATUS_SUCCESS) base = view->base;
@@ -4058,7 +4085,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemoryEx( HANDLE process, PVOID *ret, SIZE_T *s
ULONG count )
{
static const ULONG type_mask = MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN | MEM_WRITE_WATCH
- | MEM_RESET | MEM_RESERVE_PLACEHOLDER;
+ | MEM_RESET | MEM_RESERVE_PLACEHOLDER | MEM_REPLACE_PLACEHOLDER;
ULONG_PTR limit = 0;
ULONG_PTR align = 0;
@@ -4211,6 +4238,12 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
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 (type == (MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER) && !size) status = STATUS_INVALID_PARAMETER_3;
+ else if (type == (MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER) && !((view->protect & VPROT_FROMPLACEHOLDER)
+ || (view->protect & VPROT_PLACEHOLDER && size != view->size)))
+ {
+ status = STATUS_CONFLICTING_ADDRESSES;
+ }
else
{
if (!size) size = view->size;
--
2.38.1

View File

@ -0,0 +1,28 @@
From e37d37263677edfded8696ff09bc76768582e24b Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Thu, 10 Nov 2022 19:01:50 -0600
Subject: [PATCH] ntdll: Support MEM_REPLACE_PLACEHOLDER in
virtual_map_section().
Based on a patch by Nikolay Sivov.
---
dlls/ntdll/unix/virtual.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 3019c3699be..d07e980f5a7 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -2721,7 +2721,8 @@ static NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG_PTR z
server_enter_uninterrupted_section( &virtual_mutex, &sigset );
- res = map_view( &view, base, size, alloc_type & MEM_TOP_DOWN, vprot, get_zero_bits_mask( zero_bits ), 0 );
+ res = map_view( &view, base, size, alloc_type & (MEM_TOP_DOWN | MEM_REPLACE_PLACEHOLDER),
+ vprot, get_zero_bits_mask( zero_bits ), 0 );
if (res) goto done;
TRACE( "handle=%p size=%lx offset=%x%08x\n", handle, size, offset.u.HighPart, offset.u.LowPart );
--
2.38.1

View File

@ -0,0 +1,324 @@
From e47dfda03cf4f2e4c1676273da4ee8f54fabbf01 Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Wed, 9 Nov 2022 21:23:19 -0600
Subject: [PATCH] ntdll/tests: Add more tests for placeholders.
---
dlls/kernelbase/tests/process.c | 15 ++-
dlls/ntdll/tests/virtual.c | 227 +++++++++++++++++++++++---------
2 files changed, 179 insertions(+), 63 deletions(-)
diff --git a/dlls/kernelbase/tests/process.c b/dlls/kernelbase/tests/process.c
index ed213f1f7b6..0d75c6e2dda 100644
--- a/dlls/kernelbase/tests/process.c
+++ b/dlls/kernelbase/tests/process.c
@@ -168,7 +168,6 @@ 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;
@@ -206,6 +205,20 @@ static void test_VirtualAlloc2(void)
view2 = pMapViewOfFile3(section, NULL, placeholder2, 0, size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, NULL, 0);
ok(!!view2, "Failed to map a section.\n");
+ memset(&info, 0, sizeof(info));
+ VirtualQuery(placeholder1, &info, sizeof(info));
+ ok(info.AllocationProtect == PAGE_READWRITE, "Unexpected protection %#lx.\n", info.AllocationProtect);
+ ok(info.State == MEM_COMMIT, "Unexpected state %#lx.\n", info.State);
+ ok(info.Type == MEM_MAPPED, "Unexpected type %#lx.\n", info.Type);
+ ok(info.RegionSize == size, "Unexpected size.\n");
+
+ memset(&info, 0, sizeof(info));
+ VirtualQuery(placeholder2, &info, sizeof(info));
+ ok(info.AllocationProtect == PAGE_READWRITE, "Unexpected protection %#lx.\n", info.AllocationProtect);
+ ok(info.State == MEM_COMMIT, "Unexpected state %#lx.\n", info.State);
+ ok(info.Type == MEM_MAPPED, "Unexpected type %#lx.\n", info.Type);
+ ok(info.RegionSize == size, "Unexpected size.\n");
+
CloseHandle(section);
UnmapViewOfFile(view1);
UnmapViewOfFile(view2);
diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c
index 486efabaf70..b41f42ac9d1 100644
--- a/dlls/ntdll/tests/virtual.c
+++ b/dlls/ntdll/tests/virtual.c
@@ -291,9 +291,13 @@ static void check_region_size_(void *p, SIZE_T s, unsigned int line)
static void test_NtAllocateVirtualMemoryEx(void)
{
+ MEMORY_BASIC_INFORMATION mbi;
+ void *addresses[16];
SIZE_T size, size2;
char *p, *p1, *p2;
+ ULONG granularity;
NTSTATUS status;
+ ULONG_PTR count;
void *addr1;
if (!pNtAllocateVirtualMemoryEx)
@@ -329,98 +333,197 @@ static void test_NtAllocateVirtualMemoryEx(void)
status = NtAllocateVirtualMemory(NtCurrentProcess(), &addr1, 0, &size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS);
ok(status == STATUS_INVALID_PARAMETER, "Unexpected status %08lx.\n", status);
+ status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
+ PAGE_READWRITE, NULL, 0);
+ ok(status == STATUS_INVALID_PARAMETER, "Unexpected status %08lx.\n", status);
+
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 = 0x10000;
+ status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE | MEM_COMMIT | MEM_REPLACE_PLACEHOLDER,
+ PAGE_READWRITE, NULL, 0);
+ ok(!status, "Unexpected status %08lx.\n", status);
+
+ memset(addr1, 0xcc, size);
+
+ status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&addr1, &size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
+ ok(!status, "Unexpected status %08lx.\n", status);
+
+ size = 0x10000;
+ status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE | MEM_COMMIT | MEM_REPLACE_PLACEHOLDER,
+ PAGE_READONLY, NULL, 0);
+ ok(!status, "Unexpected status %08lx.\n", status);
+
+ ok(!*(unsigned int *)addr1, "Got %#x.\n", *(unsigned int *)addr1);
+
+ status = NtQueryVirtualMemory( NtCurrentProcess(), addr1, MemoryBasicInformation, &mbi, sizeof(mbi), &size );
+ ok(!status, "Unexpected status %08lx.\n", status);
+ ok(mbi.AllocationProtect == PAGE_READONLY, "Unexpected protection %#lx.\n", mbi.AllocationProtect);
+ ok(mbi.State == MEM_COMMIT, "Unexpected state %#lx.\n", mbi.State);
+ ok(mbi.Type == MEM_PRIVATE, "Unexpected type %#lx.\n", mbi.Type);
+ ok(mbi.RegionSize == 0x10000, "Unexpected size.\n");
+
+ size = 0x10000;
+ status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&addr1, &size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
+ ok(!status, "Unexpected status %08lx.\n", status);
+
+ status = NtQueryVirtualMemory( NtCurrentProcess(), addr1, MemoryBasicInformation, &mbi, sizeof(mbi), &size );
+ ok(!status, "Unexpected status %08lx.\n", status);
+ ok(mbi.AllocationProtect == PAGE_NOACCESS, "Unexpected protection %#lx.\n", mbi.AllocationProtect);
+ ok(mbi.State == MEM_RESERVE, "Unexpected state %#lx.\n", mbi.State);
+ ok(mbi.Type == MEM_PRIVATE, "Unexpected type %#lx.\n", mbi.Type);
+ ok(mbi.RegionSize == 0x10000, "Unexpected size.\n");
+
+ status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
+ PAGE_NOACCESS, NULL, 0);
+ ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status);
+
+ status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE,
+ PAGE_NOACCESS, NULL, 0);
+ ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status);
+
+ size = 0x1000;
+ status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE | MEM_REPLACE_PLACEHOLDER,
+ PAGE_NOACCESS, NULL, 0);
+ ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status);
+
+ size = 0x10000;
+ status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_COMMIT, PAGE_READWRITE, NULL, 0);
+ ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status);
+
+ size = 0x10000;
+ status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, NULL, 0);
+ ok(status == STATUS_INVALID_PARAMETER, "Unexpected status %08lx.\n", status);
+
+ size = 0x10000;
+ status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_COMMIT | MEM_REPLACE_PLACEHOLDER,
+ PAGE_READWRITE, NULL, 0);
+ ok(status == STATUS_INVALID_PARAMETER, "Unexpected status %08lx.\n", status);
+
+ size = 0x10000;
+ status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size,
+ MEM_WRITE_WATCH | MEM_RESERVE | MEM_REPLACE_PLACEHOLDER,
+ PAGE_READONLY, NULL, 0);
+ ok(!status, "Unexpected status %08lx.\n", status);
+
+ size = 0x10000;
+ status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_COMMIT, PAGE_READWRITE, NULL, 0);
+ ok(!status, "Unexpected status %08lx.\n", status);
+
+ status = NtQueryVirtualMemory( NtCurrentProcess(), addr1, MemoryBasicInformation, &mbi, sizeof(mbi), &size );
+ ok(!status, "Unexpected status %08lx.\n", status);
+ ok(mbi.AllocationProtect == PAGE_READONLY, "Unexpected protection %#lx.\n", mbi.AllocationProtect);
+ ok(mbi.State == MEM_COMMIT, "Unexpected state %#lx.\n", mbi.State);
+ ok(mbi.Type == MEM_PRIVATE, "Unexpected type %#lx.\n", mbi.Type);
+ ok(mbi.RegionSize == 0x10000, "Unexpected size.\n");
+
+ size = 0x10000;
+ count = ARRAY_SIZE(addresses);
+ status = NtGetWriteWatch( NtCurrentProcess(), WRITE_WATCH_FLAG_RESET, addr1, size,
+ addresses, &count, &granularity );
+ ok(!status, "Unexpected status %08lx.\n", status);
+ ok(!count, "Unexpected count %u.\n", (unsigned int)count);
+ trace("addr1 %p, addresses[0] %p.\n", addr1, addresses[0]);
+ *((char *)addr1 + 0x1000) = 1;
+ count = ARRAY_SIZE(addresses);
+ status = NtGetWriteWatch( NtCurrentProcess(), WRITE_WATCH_FLAG_RESET, addr1, size,
+ addresses, &count, &granularity );
+ ok(!status, "Unexpected status %08lx.\n", status);
+ ok(count == 1, "Unexpected count %u.\n", (unsigned int)count);
+ ok(addresses[0] == (char *)addr1 + 0x1000, "Unexpected address %p.\n", addresses[0]);
+
+ size = 0;
+ status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_RELEASE);
+ ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
/* Placeholder region splitting. */
+ addr1 = NULL;
+ size = 0x10000;
+ status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE,
+ PAGE_NOACCESS, NULL, 0);
+ ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
+ p = addr1;
+ status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p, &size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
+ ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status);
+ status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p, &size, MEM_RELEASE);
+ ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
+
/* Split in three regions. */
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)
- {
- 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);
- }
+ status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&addr1, &size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
+ ok(status == STATUS_CONFLICTING_ADDRESSES, "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);
+ 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);
/* 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");
-
- 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);
- }
+ size2 = 0;
+ status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&addr1, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
+ ok(status == STATUS_INVALID_PARAMETER_3, "Unexpected status %08lx.\n", status);
+
+ 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");
+
+ 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);
/* 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;
-
- 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");
- 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);
- }
+ 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");
+ 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);
}
static void test_NtAllocateVirtualMemoryEx_address_requirements(void)
--
2.38.1

View File

@ -0,0 +1,117 @@
From af2c08ba11cf85941505fc8016d4d4811575be31 Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Thu, 10 Nov 2022 19:02:50 -0600
Subject: [PATCH] ntdll: Support MEM_COALESCE_PLACEHOLDERS in
NtFreeVirtualMemory().
---
dlls/ntdll/tests/virtual.c | 53 +++++++++++++++++++++++++++++++++++++-
dlls/ntdll/unix/virtual.c | 24 +++++++++++++++++
2 files changed, 76 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c
index b41f42ac9d1..11ccca2ffb4 100644
--- a/dlls/ntdll/tests/virtual.c
+++ b/dlls/ntdll/tests/virtual.c
@@ -499,11 +499,62 @@ static void test_NtAllocateVirtualMemoryEx(void)
check_region_size(p1, size / 4);
check_region_size(p2, size - size / 4);
- status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE);
+
+ 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);
+ 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);
+ check_region_size(p1, size / 4);
+ check_region_size(p2, size - size / 4);
+
+ 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);
+
+ 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);
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 / 4;
+ status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE);
+ ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
+
/* Split in two regions, specifying second half. */
addr1 = NULL;
size = 0x10000;
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index d07e980f5a7..ced198c0463 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -4341,6 +4341,30 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
*size_ptr = size;
}
}
+ else if (type & MEM_COALESCE_PLACEHOLDERS)
+ {
+ struct file_view *next_view = RB_ENTRY_VALUE( rb_next( &view->entry ), struct file_view, entry );
+
+ if (type != (MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS)) status = STATUS_INVALID_PARAMETER_4;
+ else if (!size) status = STATUS_INVALID_PARAMETER_3;
+ else if (!next_view || (char *)view->base + view->size != next_view->base
+ || base != view->base || size != view->size + next_view->size
+ || !(view->protect & VPROT_PLACEHOLDER) || !(next_view->protect & VPROT_PLACEHOLDER))
+ {
+ status = STATUS_CONFLICTING_ADDRESSES;
+ }
+ else
+ {
+ unregister_view( view );
+ unregister_view( next_view );
+
+ view->size += next_view->size;
+ free_view( next_view );
+
+ register_view( view );
+ VIRTUAL_DEBUG_DUMP_VIEW( view );
+ }
+ }
else
{
WARN("called with wrong free type flags (%08x) !\n", type);
--
2.38.1

View File

@ -0,0 +1,54 @@
From d8506b129723188bee9daf779a19f3334459205d Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Fri, 11 Nov 2022 12:41:31 -0600
Subject: [PATCH] ntdll: Factor out unmap_view_of_section() function.
---
dlls/ntdll/unix/virtual.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index ced198c0463..219dfe8bb94 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -5012,11 +5012,7 @@ NTSTATUS WINAPI NtMapViewOfSectionEx( HANDLE handle, HANDLE process, PVOID *addr
return NtMapViewOfSection( handle, process, addr_ptr, 0, 0, offset_ptr, size_ptr, ViewShare, alloc_type, protect );
}
-/***********************************************************************
- * NtUnmapViewOfSection (NTDLL.@)
- * ZwUnmapViewOfSection (NTDLL.@)
- */
-NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr )
+NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr )
{
struct file_view *view;
NTSTATUS status = STATUS_NOT_MAPPED_VIEW;
@@ -5073,6 +5069,15 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr )
return status;
}
+/***********************************************************************
+ * NtUnmapViewOfSection (NTDLL.@)
+ * ZwUnmapViewOfSection (NTDLL.@)
+ */
+NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr )
+{
+ return unmap_view_of_section( process, addr );
+}
+
/***********************************************************************
* NtUnmapViewOfSectionEx (NTDLL.@)
* ZwUnmapViewOfSectionEx (NTDLL.@)
@@ -5080,7 +5085,7 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr )
NTSTATUS WINAPI NtUnmapViewOfSectionEx( HANDLE process, PVOID addr, ULONG flags )
{
if (flags) FIXME("Ignoring flags %#x.\n", flags);
- return NtUnmapViewOfSection( process, addr );
+ return unmap_view_of_section( process, addr );
}
/******************************************************************************
--
2.38.1

View File

@ -0,0 +1,217 @@
From 34f2b170598cff223c936c8150ff551955e2b888 Mon Sep 17 00:00:00 2001
From: Paul Gofman <pgofman@codeweavers.com>
Date: Fri, 11 Nov 2022 12:54:19 -0600
Subject: [PATCH] ntdll: Support MEM_PRESERVE_PLACEHOLDER in
NtUnmapViewOfSectionEx().
---
dlls/kernelbase/tests/process.c | 53 +++++++++++++++++++++++++++++++--
dlls/ntdll/unix/server.c | 2 +-
dlls/ntdll/unix/virtual.c | 25 +++++++++++++---
server/protocol.def | 1 +
4 files changed, 73 insertions(+), 8 deletions(-)
diff --git a/dlls/kernelbase/tests/process.c b/dlls/kernelbase/tests/process.c
index 0d75c6e2dda..5221a102863 100644
--- a/dlls/kernelbase/tests/process.c
+++ b/dlls/kernelbase/tests/process.c
@@ -41,6 +41,7 @@ static PVOID (WINAPI *pVirtualAllocFromApp)(PVOID, SIZE_T, DWORD, DWORD);
static HANDLE (WINAPI *pOpenFileMappingFromApp)( ULONG, BOOL, LPCWSTR);
static HANDLE (WINAPI *pCreateFileMappingFromApp)(HANDLE, PSECURITY_ATTRIBUTES, ULONG, ULONG64, PCWSTR);
static LPVOID (WINAPI *pMapViewOfFileFromApp)(HANDLE, ULONG, ULONG64, SIZE_T);
+static BOOL (WINAPI *pUnmapViewOfFile2)(HANDLE, void *, ULONG);
static void test_CompareObjectHandles(void)
{
@@ -166,6 +167,13 @@ static void test_VirtualAlloc2(void)
ret = VirtualFree(addr, 0, MEM_RELEASE);
ok(ret, "Unexpected return value %d, error %lu.\n", ret, GetLastError());
+ placeholder1 = pVirtualAlloc2(NULL, NULL, 2 * size, MEM_RESERVE, PAGE_NOACCESS, NULL, 0);
+ ok(!!placeholder1, "Failed to create a placeholder range.\n");
+ ret = VirtualFree(placeholder1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
+ ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got ret %d, error %lu.\n", ret, GetLastError());
+ ret = VirtualFree(placeholder1, 0, MEM_RELEASE);
+ ok(ret, "Unexpected return value %d, error %lu.\n", ret, GetLastError());
+
/* Placeholder splitting functionality */
placeholder1 = pVirtualAlloc2(NULL, NULL, 2 * size, MEM_RESERVE_PLACEHOLDER | MEM_RESERVE, PAGE_NOACCESS, NULL, 0);
ok(!!placeholder1, "Failed to create a placeholder range.\n");
@@ -199,11 +207,20 @@ static void test_VirtualAlloc2(void)
section = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, NULL);
ok(!!section, "Failed to create a section.\n");
- view1 = pMapViewOfFile3(section, NULL, placeholder1, 0, size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, NULL, 0);
+ view1 = pMapViewOfFile3(section, NULL, NULL, 0, size, 0, PAGE_READWRITE, NULL, 0);
ok(!!view1, "Failed to map a section.\n");
+ ret = VirtualFree( view1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER );
+ ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got ret %d, error %lu.\n", ret, GetLastError());
+ ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, MEM_PRESERVE_PLACEHOLDER);
+ ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got ret %d, error %lu.\n", ret, GetLastError());
+ ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, 0);
+ ok(ret, "Got error %lu.\n", GetLastError());
+
+ view1 = pMapViewOfFile3(section, NULL, placeholder1, 0, size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, NULL, 0);
+ ok(view1 == placeholder1, "Address does not match.\n");
view2 = pMapViewOfFile3(section, NULL, placeholder2, 0, size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, NULL, 0);
- ok(!!view2, "Failed to map a section.\n");
+ ok(view2 == placeholder2, "Address does not match.\n");
memset(&info, 0, sizeof(info));
VirtualQuery(placeholder1, &info, sizeof(info));
@@ -220,7 +237,34 @@ static void test_VirtualAlloc2(void)
ok(info.RegionSize == size, "Unexpected size.\n");
CloseHandle(section);
- UnmapViewOfFile(view1);
+ ret = pUnmapViewOfFile2(NULL, view1, MEM_PRESERVE_PLACEHOLDER);
+ ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got error %lu.\n", GetLastError());
+
+ ret = VirtualFree( placeholder1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER );
+ ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got ret %d, error %lu.\n", ret, GetLastError());
+
+ ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, MEM_PRESERVE_PLACEHOLDER);
+ ok(ret, "Got error %lu.\n", GetLastError());
+ 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");
+
+ ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, MEM_PRESERVE_PLACEHOLDER);
+ ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got error %lu.\n", GetLastError());
+
+ ret = UnmapViewOfFile(view1);
+ ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got error %lu.\n", GetLastError());
+
+ ret = VirtualFree( placeholder1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER );
+ ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got ret %d, error %lu.\n", ret, GetLastError());
+ ret = VirtualFreeEx(GetCurrentProcess(), placeholder1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER );
+ ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got ret %d, error %lu.\n", ret, GetLastError());
+ ret = VirtualFree(placeholder1, 0, MEM_RELEASE);
+ ok(ret, "Got error %lu.\n", GetLastError());
+
UnmapViewOfFile(view2);
VirtualFree(placeholder1, 0, MEM_RELEASE);
@@ -250,6 +294,8 @@ static void test_VirtualAlloc2(void)
p1 = p;
p2 = p + size / 2;
+ ret = VirtualFree(p1, 0, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
+ ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got ret %d, error %lu.\n", ret, GetLastError());
ret = VirtualFree(p1, size / 2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
ok(ret, "Failed to split a placeholder.\n");
check_region_size(p1, size / 2);
@@ -447,6 +493,7 @@ static void init_funcs(void)
X(VirtualAlloc2);
X(VirtualAlloc2FromApp);
X(VirtualAllocFromApp);
+ X(UnmapViewOfFile2);
hmod = GetModuleHandleA("ntdll.dll");
diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c
index 630abe74c80..cba874ee6a8 100644
--- a/dlls/ntdll/unix/server.c
+++ b/dlls/ntdll/unix/server.c
@@ -572,7 +572,7 @@ static void invoke_system_apc( const apc_call_t *call, apc_result_t *result, BOO
result->type = call->type;
addr = wine_server_get_ptr( call->unmap_view.addr );
if ((ULONG_PTR)addr == call->unmap_view.addr)
- result->unmap_view.status = NtUnmapViewOfSection( NtCurrentProcess(), addr );
+ result->unmap_view.status = NtUnmapViewOfSectionEx( NtCurrentProcess(), addr, call->unmap_view.flags );
else
result->unmap_view.status = STATUS_INVALID_PARAMETER;
break;
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 219dfe8bb94..84a4e331ad7 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -5012,7 +5012,7 @@ NTSTATUS WINAPI NtMapViewOfSectionEx( HANDLE handle, HANDLE process, PVOID *addr
return NtMapViewOfSection( handle, process, addr_ptr, 0, 0, offset_ptr, size_ptr, ViewShare, alloc_type, protect );
}
-NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr )
+static NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr, ULONG flags )
{
struct file_view *view;
NTSTATUS status = STATUS_NOT_MAPPED_VIEW;
@@ -5027,6 +5027,7 @@ NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr )
call.unmap_view.type = APC_UNMAP_VIEW;
call.unmap_view.addr = wine_server_client_ptr( addr );
+ call.unmap_view.flags = flags;
status = server_queue_process_apc( process, &call, &result );
if (status == STATUS_SUCCESS) status = result.unmap_view.status;
return status;
@@ -5035,6 +5036,11 @@ NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr )
server_enter_uninterrupted_section( &virtual_mutex, &sigset );
if ((view = find_view( addr, 0 )) && !is_view_valloc( view ))
{
+ if (flags & MEM_PRESERVE_PLACEHOLDER && !(view->protect & VPROT_FROMPLACEHOLDER))
+ {
+ status = STATUS_CONFLICTING_ADDRESSES;
+ goto done;
+ }
if (view->protect & VPROT_SYSTEM)
{
struct builtin_module *builtin;
@@ -5061,10 +5067,21 @@ NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr )
if (!status)
{
if (view->protect & SEC_IMAGE) release_builtin_module( view->base );
- delete_view( view );
+ if (flags & MEM_PRESERVE_PLACEHOLDER)
+ {
+ view->protect = VPROT_PLACEHOLDER;
+ set_page_vprot( view->base, view->size, 0 );
+ if (anon_mmap_fixed(view->base, view->size, 0, 0) != view->base)
+ ERR("anon_mmap_fixed failed, err %s.\n", strerror(errno));
+ }
+ else
+ {
+ delete_view( view );
+ }
}
else FIXME( "failed to unmap %p %x\n", view->base, status );
}
+done:
server_leave_uninterrupted_section( &virtual_mutex, &sigset );
return status;
}
@@ -5075,7 +5092,7 @@ NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr )
*/
NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr )
{
- return unmap_view_of_section( process, addr );
+ return unmap_view_of_section( process, addr, 0 );
}
/***********************************************************************
@@ -5085,7 +5102,7 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr )
NTSTATUS WINAPI NtUnmapViewOfSectionEx( HANDLE process, PVOID addr, ULONG flags )
{
if (flags) FIXME("Ignoring flags %#x.\n", flags);
- return unmap_view_of_section( process, addr );
+ return unmap_view_of_section( process, addr, flags );
}
/******************************************************************************
diff --git a/server/protocol.def b/server/protocol.def
index 9a832cd3a06..35408413249 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -602,6 +602,7 @@ typedef union
enum apc_type type; /* APC_UNMAP_VIEW */
int __pad;
client_ptr_t addr; /* view address */
+ unsigned int flags; /* unmap flags */
} unmap_view;
struct
{
--
2.38.1

View File

View File

@ -139,6 +139,7 @@ patch_enable_all ()
enable_ntdll_Manifest_Range="$1"
enable_ntdll_NtQuerySection="$1"
enable_ntdll_NtSetLdtEntries="$1"
enable_ntdll_Placeholders="$1"
enable_ntdll_ProcessQuotaLimits="$1"
enable_ntdll_RtlQueryPackageIdentity="$1"
enable_ntdll_Serial_Port_Detection="$1"
@ -430,6 +431,9 @@ patch_enable ()
ntdll-NtSetLdtEntries)
enable_ntdll_NtSetLdtEntries="$2"
;;
ntdll-Placeholders)
enable_ntdll_Placeholders="$2"
;;
ntdll-ProcessQuotaLimits)
enable_ntdll_ProcessQuotaLimits="$2"
;;
@ -2191,6 +2195,32 @@ if test "$enable_ntdll_NtSetLdtEntries" -eq 1; then
patch_apply ntdll-NtSetLdtEntries/0002-libs-wine-Allow-to-modify-reserved-LDT-entries.patch
fi
# Patchset ntdll-Placeholders
# |
# | Modified files:
# | * dlls/kernelbase/memory.c, dlls/kernelbase/tests/process.c, dlls/ntdll/tests/virtual.c, dlls/ntdll/unix/server.c,
# | dlls/ntdll/unix/virtual.c, server/protocol.def
# |
if test "$enable_ntdll_Placeholders" -eq 1; then
patch_apply ntdll-Placeholders/0001-ntdll-tests-Add-tests-for-freeing-a-part-of-view.patch
patch_apply ntdll-Placeholders/0002-kernelbase-Validate-nonzero-size-for-MEM_RELEASE-in-.patch
patch_apply ntdll-Placeholders/0003-ntdll-Fix-size-validation-in-NtFreeVirtualMemory.patch
patch_apply ntdll-Placeholders/0004-ntdll-Fully-support-unaligned-views-in-free-ranges-m.patch
patch_apply ntdll-Placeholders/0005-ntdll-Factor-out-some-view-manipulation-functions.patch
patch_apply ntdll-Placeholders/0006-ntdll-Support-partial-view-release-in-NtFreeVirtualM.patch
patch_apply ntdll-Placeholders/0007-ntdll-Add-logging-for-free-ranges.patch
patch_apply ntdll-Placeholders/0008-ntdll-Handle-NULL-process-handle-in-MapViewOfFile3.patch
patch_apply ntdll-Placeholders/0009-ntdll-Support-MEM_PRESERVE_PLACEHOLDER-in-NtFreeVirt.patch
patch_apply ntdll-Placeholders/0010-ntdll-Pass-allocation-type-to-map_view.patch
patch_apply ntdll-Placeholders/0011-ntdll-Support-MEM_RESERVE_PLACEHOLDER-in-NtAllocateV.patch
patch_apply ntdll-Placeholders/0012-ntdll-Support-MEM_REPLACE_PLACEHOLDER-in-NtAllocateV.patch
patch_apply ntdll-Placeholders/0013-ntdll-Support-MEM_REPLACE_PLACEHOLDER-in-virtual_map.patch
patch_apply ntdll-Placeholders/0014-ntdll-tests-Add-more-tests-for-placeholders.patch
patch_apply ntdll-Placeholders/0015-ntdll-Support-MEM_COALESCE_PLACEHOLDERS-in-NtFreeVir.patch
patch_apply ntdll-Placeholders/0016-ntdll-Factor-out-unmap_view_of_section-function.patch
patch_apply ntdll-Placeholders/0017-ntdll-Support-MEM_PRESERVE_PLACEHOLDER-in-NtUnmapVie.patch
fi
# Patchset ntdll-ProcessQuotaLimits
# |
# | This patchset fixes the following Wine bugs: