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@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-11-19 11:04:30 +01:00
parent 32fb017d4a
commit 7d2a7b94aa
2 changed files with 53 additions and 7 deletions

View File

@ -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");

View File

@ -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;