Alexandre Julliard : ntdll: Fix handling of zero size with MEM_DECOMMIT.

Alexandre Julliard julliard at winehq.org
Fri Nov 19 15:45:31 CST 2021


Module: wine
Branch: master
Commit: 7d2a7b94aad8a776a2ee3031a18bb3b53d5925cd
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=7d2a7b94aad8a776a2ee3031a18bb3b53d5925cd

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Fri Nov 19 11:04:30 2021 +0100

ntdll: Fix handling of zero size with MEM_DECOMMIT.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52023
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/tests/virtual.c | 43 +++++++++++++++++++++++++++++++++++++++++++
 dlls/ntdll/unix/virtual.c  | 17 ++++++++++-------
 2 files changed, 53 insertions(+), 7 deletions(-)

diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c
index 5f155b1a147..53adee5896d 100644
--- a/dlls/ntdll/tests/virtual.c
+++ b/dlls/ntdll/tests/virtual.c
@@ -219,6 +219,49 @@ static void test_NtAllocateVirtualMemory(void)
     status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_RELEASE);
     ok(status == STATUS_SUCCESS, "NtFreeVirtualMemory failed\n");
 
+    /* NtFreeVirtualMemory tests */
+
+    size = 0x10000;
+    addr1 = NULL;
+    status = NtAllocateVirtualMemory(NtCurrentProcess(), &addr1, 0, &size,
+                                     MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+    ok(status == STATUS_SUCCESS, "NtAllocateVirtualMemory returned %08x\n", status);
+
+    size = 2;
+    addr2 = (char *)addr1 + 0x1fff;
+    status = NtFreeVirtualMemory(NtCurrentProcess(), &addr2, &size, MEM_DECOMMIT);
+    ok(status == STATUS_SUCCESS, "NtFreeVirtualMemory failed %x\n", status);
+    ok( size == 0x2000, "wrong size %lx\n", size );
+    ok( addr2 == (char *)addr1 + 0x1000, "wrong addr %p\n", addr2 );
+
+    size = 0;
+    addr2 = (char *)addr1 + 0x1001;
+    status = NtFreeVirtualMemory(NtCurrentProcess(), &addr2, &size, MEM_DECOMMIT);
+    ok(status == STATUS_FREE_VM_NOT_AT_BASE, "NtFreeVirtualMemory failed %x\n", status);
+    ok( size == 0, "wrong size %lx\n", size );
+    ok( addr2 == (char *)addr1 + 0x1001, "wrong addr %p\n", addr2 );
+
+    size = 0;
+    addr2 = (char *)addr1 + 0xffe;
+    status = NtFreeVirtualMemory(NtCurrentProcess(), &addr2, &size, MEM_DECOMMIT);
+    ok(status == STATUS_SUCCESS, "NtFreeVirtualMemory failed %x\n", status);
+    ok( size == 0, "wrong size %lx\n", size );
+    ok( addr2 == addr1, "wrong addr %p\n", addr2 );
+
+    size = 0;
+    addr2 = (char *)addr1 + 0x1001;
+    status = NtFreeVirtualMemory(NtCurrentProcess(), &addr2, &size, MEM_RELEASE);
+    ok(status == STATUS_FREE_VM_NOT_AT_BASE, "NtFreeVirtualMemory failed %x\n", status);
+    ok( size == 0, "wrong size %lx\n", size );
+    ok( addr2 == (char *)addr1 + 0x1001, "wrong addr %p\n", addr2 );
+
+    size = 0;
+    addr2 = (char *)addr1 + 0xfff;
+    status = NtFreeVirtualMemory(NtCurrentProcess(), &addr2, &size, MEM_RELEASE);
+    ok(status == STATUS_SUCCESS, "NtFreeVirtualMemory failed %x\n", status);
+    ok( size == 0x10000, "wrong size %lx\n", size );
+    ok( addr2 == addr1, "wrong addr %p\n", addr2 );
+
     if (!pNtAllocateVirtualMemoryEx)
     {
         win_skip("NtAllocateVirtualMemoryEx() is missing\n");
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index f62ca1f5f01..5873a3e2335 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -2121,13 +2121,14 @@ static SIZE_T get_committed_size( struct file_view *view, void *base, BYTE *vpro
 
 
 /***********************************************************************
- *           decommit_view
+ *           decommit_pages
  *
  * Decommit some pages of a given view.
  * virtual_mutex must be held by caller.
  */
 static NTSTATUS decommit_pages( struct file_view *view, size_t start, size_t size )
 {
+    if (!size) size = view->size;
     if (anon_mmap_fixed( (char *)view->base + start, size, PROT_NONE, 0 ) != MAP_FAILED)
     {
         set_page_vprot_bits( (char *)view->base + start, size, 0, VPROT_COMMITTED );
@@ -3966,7 +3967,7 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
 
     /* Fix the parameters */
 
-    size = ROUND_SIZE( addr, size );
+    if (size) size = ROUND_SIZE( addr, size );
     base = ROUND_ADDR( addr, page_mask );
 
     server_enter_uninterrupted_section( &virtual_mutex, &sigset );
@@ -3975,7 +3976,7 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
     if (!base)
     {
         /* address 1 is magic to mean release reserved space */
-        if (addr == (void *)1 && !*size_ptr && type == MEM_RELEASE) virtual_release_address_space();
+        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 ))
@@ -3986,17 +3987,19 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
     {
         /* Free the pages */
 
-        if (size || (base != view->base)) status = STATUS_INVALID_PARAMETER;
+        if (size) status = STATUS_INVALID_PARAMETER;
+        else if (base != view->base) status = STATUS_FREE_VM_NOT_AT_BASE;
         else
         {
-            delete_view( view );
             *addr_ptr = base;
-            *size_ptr = size;
+            *size_ptr = view->size;
+            delete_view( view );
         }
     }
     else if (type == MEM_DECOMMIT)
     {
-        status = decommit_pages( view, base - (char *)view->base, size );
+        if (!size && base != view->base) status = STATUS_FREE_VM_NOT_AT_BASE;
+        else status = decommit_pages( view, base - (char *)view->base, size );
         if (status == STATUS_SUCCESS)
         {
             *addr_ptr = base;




More information about the wine-cvs mailing list