Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58531
-- v3: ntdll: Reimplement get_memory_region_info() on top of get_memory_region_size(). ntdll: Factor out get_memory_region_size() function. ntdll/tests: Add more tests for NtQueryVirtualMemory( MemoryRegionInformation ).
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/virtual.c | 134 ++++++++++++++++++++++++++++++++++++- 1 file changed, 133 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index c48652f0f65..d3ee66e3716 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -298,6 +298,7 @@ static void check_region_size_(void *p, SIZE_T s, unsigned int line)
static void test_NtAllocateVirtualMemoryEx(void) { + MEMORY_REGION_INFORMATION mri; MEMORY_BASIC_INFORMATION mbi; MEM_EXTENDED_PARAMETER ext[2]; char *p, *p1, *p2, *p3; @@ -615,6 +616,35 @@ static void test_NtAllocateVirtualMemoryEx(void) ok(p2 == p1 + size / 2, "Unexpected addr %p, expected %p.\n", p2, p1 + size / 2); check_region_size(p1, size / 2); check_region_size(p2, size / 2); + + status = NtQueryVirtualMemory( NtCurrentProcess(), p1, MemoryBasicInformation, &mbi, sizeof(mbi), NULL ); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status ); + ok( mbi.AllocationBase == p1, "got %p.\n", mbi.AllocationBase ); + ok( mbi.Type == MEM_PRIVATE, "got %#lx.\n", mbi.Type ); + ok( mbi.State == MEM_RESERVE, "got %#lx.\n", mbi.State ); + ok( mbi.RegionSize == size / 2, "Unexpected size %Iu, expected %Iu.\n", mbi.RegionSize, size / 2 ); + ok( mbi.AllocationProtect == PAGE_NOACCESS, "got %#lx.\n", mbi.AllocationProtect ); + status = NtQueryVirtualMemory( NtCurrentProcess(), p1, MemoryRegionInformation, &mri, sizeof(mri), NULL ); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status ); + ok( mri.AllocationBase == p1, "got %p.\n", mri.AllocationBase ); + ok( mri.RegionSize == size / 2, "Unexpected size %Iu, expected %Iu.\n", mri.RegionSize, size / 2 ); + ok( !mri.CommitSize, "Unexpected size %Iu.\n", mri.CommitSize ); + ok( mri.AllocationProtect == PAGE_NOACCESS, "got %#lx.\n", mri.AllocationProtect ); + + status = NtQueryVirtualMemory( NtCurrentProcess(), p2, MemoryBasicInformation, &mbi, sizeof(mbi), NULL ); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status ); + ok( mbi.AllocationBase == p2, "got %p.\n", mbi.AllocationBase ); + ok( mbi.Type == MEM_PRIVATE, "got %#lx.\n", mbi.Type ); + ok( mbi.State == MEM_RESERVE, "got %#lx.\n", mbi.State ); + ok( mbi.RegionSize == size / 2, "Unexpected size %Iu, expected %Iu.\n", mbi.RegionSize, size / 2 ); + ok( mbi.AllocationProtect == PAGE_NOACCESS, "got %#lx.\n", mbi.AllocationProtect ); + status = NtQueryVirtualMemory( NtCurrentProcess(), p2, MemoryRegionInformation, &mri, sizeof(mri), NULL ); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status ); + ok( mri.AllocationBase == p2, "got %p.\n", mri.AllocationBase ); + ok( mri.RegionSize == size / 2, "Unexpected size %Iu, expected %Iu.\n", mri.RegionSize, size / 2 ); + ok( !mri.CommitSize, "Unexpected size %Iu.\n", mri.CommitSize ); + ok( mri.AllocationProtect == PAGE_NOACCESS, "got %#lx.\n", mri.AllocationProtect ); + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE); ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); ok(size2 == 0x8000, "Unexpected size %#Ix.\n", size2); @@ -2633,7 +2663,8 @@ static void test_query_region_information(void) SIZE_T len, size; NTSTATUS status; HANDLE mapping; - void *ptr; + void *ptr, *addr; + ULONG old;
size = 0x10000; ptr = NULL; @@ -2665,6 +2696,7 @@ static void test_query_region_information(void) ok(!info.MappedPhysical, "Unexpected flag %d.\n", info.MappedPhysical); ok(!info.DirectMapped, "Unexpected flag %d.\n", info.DirectMapped); ok(info.RegionSize == size, "Unexpected region size.\n"); + ok(!info.CommitSize, "Unexpected commit size %#Ix.\n", info.CommitSize);
size = 0; status = NtFreeVirtualMemory(NtCurrentProcess(), &ptr, &size, MEM_RELEASE); @@ -2688,11 +2720,49 @@ static void test_query_region_information(void) ok(!info.MappedPhysical, "Unexpected flag %d.\n", info.MappedPhysical); ok(!info.DirectMapped, "Unexpected flag %d.\n", info.DirectMapped); ok(info.RegionSize == size, "Unexpected region size.\n"); + ok(info.CommitSize == size, "Unexpected commit size %#Ix.\n", info.CommitSize); + + addr = (char *)ptr + 0x1000; + size = 0x1000; + status = NtProtectVirtualMemory(NtCurrentProcess(), &addr, &size, PAGE_NOACCESS, &old ); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + status = NtQueryVirtualMemory(NtCurrentProcess(), ptr, MemoryRegionInformation, &info, sizeof(info), &len); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(info.AllocationBase == ptr, "Unexpected base %p.\n", info.AllocationBase); + ok(info.AllocationProtect == PAGE_READWRITE, "Unexpected protection %lu.\n", info.AllocationProtect); + ok(!info.Private, "Unexpected flag %d.\n", info.Private); + ok(!info.MappedDataFile, "Unexpected flag %d.\n", info.MappedDataFile); + ok(!info.MappedImage, "Unexpected flag %d.\n", info.MappedImage); + ok(!info.MappedPageFile, "Unexpected flag %d.\n", info.MappedPageFile); + ok(!info.MappedPhysical, "Unexpected flag %d.\n", info.MappedPhysical); + ok(!info.DirectMapped, "Unexpected flag %d.\n", info.DirectMapped); + todo_wine ok(info.RegionSize == 0x10000, "Unexpected region size %#Ix.\n", info.RegionSize); + todo_wine ok(info.CommitSize == 0x10000, "Unexpected commit size %#Ix.\n", info.CommitSize); + + status = NtQueryVirtualMemory(NtCurrentProcess(), (char *)ptr + 0x1000, MemoryRegionInformation, &info, sizeof(info), &len); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(info.AllocationBase == ptr, "Unexpected base %p.\n", info.AllocationBase); + ok(info.AllocationProtect == PAGE_READWRITE, "Unexpected protection %lu.\n", info.AllocationProtect); + ok(!info.Private, "Unexpected flag %d.\n", info.Private); + ok(!info.MappedDataFile, "Unexpected flag %d.\n", info.MappedDataFile); + ok(!info.MappedImage, "Unexpected flag %d.\n", info.MappedImage); + ok(!info.MappedPageFile, "Unexpected flag %d.\n", info.MappedPageFile); + ok(!info.MappedPhysical, "Unexpected flag %d.\n", info.MappedPhysical); + ok(!info.DirectMapped, "Unexpected flag %d.\n", info.DirectMapped); + todo_wine ok(info.RegionSize == 0x10000, "Unexpected region size %#Ix.\n", info.RegionSize); + todo_wine ok(info.CommitSize == 0x10000, "Unexpected commit size %#Ix.\n", info.CommitSize);
size = 0; status = NtFreeVirtualMemory(NtCurrentProcess(), &ptr, &size, MEM_RELEASE); ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
+ memset(&info, 0xcc, sizeof(info)); + status = NtQueryVirtualMemory(NtCurrentProcess(), ptr, MemoryRegionInformation, &info, sizeof(info), &len); + todo_wine ok(status == STATUS_INVALID_ADDRESS, "Unexpected status %08lx.\n", status); + todo_wine ok(info.AllocationBase == (void *)(ULONG_PTR)0xcccccccccccccccc, "got %p.\n", info.AllocationBase); + todo_wine ok(info.AllocationProtect == 0xcccccccc, "Unexpected protection %lu.\n", info.AllocationProtect); + todo_wine ok(info.RegionType == 0xcccccccc, "got %#lx.\n", info.RegionType); + /* Pagefile mapping */ mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL); ok(mapping != 0, "CreateFileMapping failed\n"); @@ -2715,6 +2785,68 @@ static void test_query_region_information(void) ok(!info.MappedPhysical, "Unexpected flag %d.\n", info.MappedPhysical); ok(!info.DirectMapped, "Unexpected flag %d.\n", info.DirectMapped); ok(info.RegionSize == 4096, "Unexpected region size.\n"); + todo_wine ok(!info.CommitSize, "Unexpected commit size %#Ix.\n", info.CommitSize); + + status = NtUnmapViewOfSection(NtCurrentProcess(), ptr); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + + ptr = NULL; + size = 0; + offset.QuadPart = 0; + status = NtMapViewOfSection(mapping, NtCurrentProcess(), &ptr, 0, 0, &offset, &size, 1, 0, PAGE_WRITECOPY); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + + memset(&info, 0x11, sizeof(info)); + status = NtQueryVirtualMemory(NtCurrentProcess(), ptr, MemoryRegionInformation, &info, sizeof(info), &len); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(info.AllocationBase == ptr, "Unexpected base %p.\n", info.AllocationBase); + ok(info.AllocationProtect == PAGE_WRITECOPY, "Unexpected protection %lu.\n", info.AllocationProtect); + ok(!info.Private, "Unexpected flag %d.\n", info.Private); + ok(!info.MappedDataFile, "Unexpected flag %d.\n", info.MappedDataFile); + ok(!info.MappedImage, "Unexpected flag %d.\n", info.MappedImage); + ok(!info.MappedPageFile, "Unexpected flag %d.\n", info.MappedPageFile); + ok(!info.MappedPhysical, "Unexpected flag %d.\n", info.MappedPhysical); + ok(!info.DirectMapped, "Unexpected flag %d.\n", info.DirectMapped); + ok(info.RegionSize == 4096, "Unexpected region size.\n"); + ok(info.CommitSize == 4096, "Unexpected commit size %#Ix.\n", info.CommitSize); + + *(int *)ptr = 1; + memset(&info, 0x11, sizeof(info)); + status = NtQueryVirtualMemory(NtCurrentProcess(), ptr, MemoryRegionInformation, &info, sizeof(info), &len); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(info.AllocationBase == ptr, "Unexpected base %p.\n", info.AllocationBase); + ok(info.AllocationProtect == PAGE_WRITECOPY, "Unexpected protection %lu.\n", info.AllocationProtect); + ok(!info.Private, "Unexpected flag %d.\n", info.Private); + ok(!info.MappedDataFile, "Unexpected flag %d.\n", info.MappedDataFile); + ok(!info.MappedImage, "Unexpected flag %d.\n", info.MappedImage); + ok(!info.MappedPageFile, "Unexpected flag %d.\n", info.MappedPageFile); + ok(!info.MappedPhysical, "Unexpected flag %d.\n", info.MappedPhysical); + ok(!info.DirectMapped, "Unexpected flag %d.\n", info.DirectMapped); + ok(info.RegionSize == 4096, "Unexpected region size.\n"); + ok(info.CommitSize == 4096, "Unexpected commit size %#Ix.\n", info.CommitSize); + + status = NtUnmapViewOfSection(NtCurrentProcess(), ptr); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + + ptr = NULL; + size = 0; + offset.QuadPart = 0; + status = NtMapViewOfSection(mapping, NtCurrentProcess(), &ptr, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + + memset(&info, 0x11, sizeof(info)); + status = NtQueryVirtualMemory(NtCurrentProcess(), ptr, MemoryRegionInformation, &info, sizeof(info), &len); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(info.AllocationBase == ptr, "Unexpected base %p.\n", info.AllocationBase); + ok(info.AllocationProtect == PAGE_READWRITE, "Unexpected protection %lu.\n", info.AllocationProtect); + ok(!info.Private, "Unexpected flag %d.\n", info.Private); + ok(!info.MappedDataFile, "Unexpected flag %d.\n", info.MappedDataFile); + ok(!info.MappedImage, "Unexpected flag %d.\n", info.MappedImage); + ok(!info.MappedPageFile, "Unexpected flag %d.\n", info.MappedPageFile); + ok(!info.MappedPhysical, "Unexpected flag %d.\n", info.MappedPhysical); + ok(!info.DirectMapped, "Unexpected flag %d.\n", info.DirectMapped); + ok(info.RegionSize == 4096, "Unexpected region size.\n"); + todo_wine ok(!info.CommitSize, "Unexpected commit size %#Ix.\n", info.CommitSize);
status = NtUnmapViewOfSection(NtCurrentProcess(), ptr); ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status);
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/unix/virtual.c | 146 +++++++++++++++++++++----------------- 1 file changed, 82 insertions(+), 64 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index e733e3ffdd6..a57da1b5d09 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -5407,105 +5407,123 @@ NTSTATUS WINAPI NtProtectVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T }
-static unsigned int fill_basic_memory_info( const void *addr, MEMORY_BASIC_INFORMATION *info ) +static struct file_view *get_memory_region_size( char *base, char **region_start, char **region_end, + BOOL *fake_reserved ) { - char *base, *alloc_base = 0, *alloc_end = working_set_limit; struct wine_rb_entry *ptr; struct file_view *view; - sigset_t sigset;
- base = ROUND_ADDR( addr, page_mask ); - - if (is_beyond_limit( base, 1, working_set_limit )) return STATUS_INVALID_PARAMETER; + *fake_reserved = FALSE; + *region_start = NULL; + *region_end = working_set_limit;
- /* Find the view containing the address */ - - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); ptr = views_tree.root; while (ptr) { view = WINE_RB_ENTRY_VALUE( ptr, struct file_view, entry ); if ((char *)view->base > base) { - alloc_end = view->base; + *region_end = view->base; ptr = ptr->left; } else if ((char *)view->base + view->size <= base) { - alloc_base = (char *)view->base + view->size; + *region_start = (char *)view->base + view->size; ptr = ptr->right; } else { - alloc_base = view->base; - alloc_end = (char *)view->base + view->size; + *region_start = view->base; + *region_end = (char *)view->base + view->size; break; } } - - /* Fill the info structure */ - - info->BaseAddress = base; - info->RegionSize = alloc_end - base; - - if (!ptr) +#ifdef __i386__ { - info->State = MEM_FREE; - info->Protect = PAGE_NOACCESS; - info->AllocationBase = 0; - info->AllocationProtect = 0; - info->Type = 0; + struct reserved_area *area;
-#ifdef __i386__ + if (ptr) return view; /* on i386, pretend that space outside of a reserved area is allocated, * so that the app doesn't believe it's fully available */ + LIST_FOR_EACH_ENTRY( area, &reserved_areas, struct reserved_area, entry ) { - struct reserved_area *area; - BOOL in_reserved = FALSE; + char *area_start = area->base; + char *area_end = area_start + area->size;
- LIST_FOR_EACH_ENTRY( area, &reserved_areas, struct reserved_area, entry ) + if (area_end <= base) { - char *area_start = area->base; - char *area_end = area_start + area->size; + if (*region_start < area_end) *region_start = area_end; + continue; + } + if (area_start <= base || area_start <= (char *)address_space_start) + { + if (area_end < *region_end) *region_end = area_end; + return NULL; + } + /* report the remaining part of the 64K after the view as free */ + if ((UINT_PTR)*region_start & granularity_mask) + { + char *next = (char *)ROUND_ADDR( *region_start, granularity_mask ) + granularity_mask + 1;
- if (area_end <= base) - { - if (alloc_base < area_end) alloc_base = area_end; - continue; - } - if (area_start <= base || area_start <= (char *)address_space_start) + if (base < next) { - if (area_end < alloc_end) info->RegionSize = area_end - base; - in_reserved = TRUE; - break; - } - /* report the remaining part of the 64K after the view as free */ - if ((UINT_PTR)alloc_base & granularity_mask) - { - char *next = (char *)ROUND_ADDR( alloc_base, granularity_mask ) + granularity_mask + 1; - - if (base < next) - { - info->RegionSize = min( next, alloc_end ) - base; - in_reserved = TRUE; - break; - } - else alloc_base = base; + *region_end = min( next, *region_end ); + return NULL; } - /* pretend it's allocated */ - if (area_start < alloc_end) info->RegionSize = area_start - base; - break; - } - if (!in_reserved) - { - info->State = MEM_RESERVE; - info->Protect = PAGE_NOACCESS; - info->AllocationBase = alloc_base; - info->AllocationProtect = PAGE_NOACCESS; - info->Type = MEM_PRIVATE; + else *region_start = base; } + /* pretend it's allocated */ + if (area_start < *region_end) *region_end = area_start; + break; } + *fake_reserved = TRUE; + return NULL; + } +#else + return ptr ? view : NULL; #endif +} + + +static unsigned int fill_basic_memory_info( const void *addr, MEMORY_BASIC_INFORMATION *info ) +{ + char *base, *alloc_base, *alloc_end; + struct file_view *view; + BOOL fake_reserved; + sigset_t sigset; + + base = ROUND_ADDR( addr, page_mask ); + + if (is_beyond_limit( base, 1, working_set_limit )) return STATUS_INVALID_PARAMETER; + + /* Find the view containing the address */ + + server_enter_uninterrupted_section( &virtual_mutex, &sigset ); + view = get_memory_region_size( base, &alloc_base, &alloc_end, &fake_reserved ); + + /* Fill the info structure */ + + info->BaseAddress = base; + info->RegionSize = alloc_end - base; + + if (!view) + { + if (fake_reserved) + { + info->State = MEM_RESERVE; + info->Protect = PAGE_NOACCESS; + info->AllocationBase = alloc_base; + info->AllocationProtect = PAGE_NOACCESS; + info->Type = MEM_PRIVATE; + } + else + { + info->State = MEM_FREE; + info->Protect = PAGE_NOACCESS; + info->AllocationBase = 0; + info->AllocationProtect = 0; + info->Type = 0; + } } else {
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/virtual.c | 25 +++++++++-------- dlls/ntdll/unix/virtual.c | 57 +++++++++++++++++++++++++++++++------- 2 files changed, 60 insertions(+), 22 deletions(-)
diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index d3ee66e3716..ff7e82260d1 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -2736,8 +2736,8 @@ static void test_query_region_information(void) ok(!info.MappedPageFile, "Unexpected flag %d.\n", info.MappedPageFile); ok(!info.MappedPhysical, "Unexpected flag %d.\n", info.MappedPhysical); ok(!info.DirectMapped, "Unexpected flag %d.\n", info.DirectMapped); - todo_wine ok(info.RegionSize == 0x10000, "Unexpected region size %#Ix.\n", info.RegionSize); - todo_wine ok(info.CommitSize == 0x10000, "Unexpected commit size %#Ix.\n", info.CommitSize); + ok(info.RegionSize == 0x10000, "Unexpected region size %#Ix.\n", info.RegionSize); + ok(info.CommitSize == 0x10000, "Unexpected commit size %#Ix.\n", info.CommitSize);
status = NtQueryVirtualMemory(NtCurrentProcess(), (char *)ptr + 0x1000, MemoryRegionInformation, &info, sizeof(info), &len); ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); @@ -2749,8 +2749,8 @@ static void test_query_region_information(void) ok(!info.MappedPageFile, "Unexpected flag %d.\n", info.MappedPageFile); ok(!info.MappedPhysical, "Unexpected flag %d.\n", info.MappedPhysical); ok(!info.DirectMapped, "Unexpected flag %d.\n", info.DirectMapped); - todo_wine ok(info.RegionSize == 0x10000, "Unexpected region size %#Ix.\n", info.RegionSize); - todo_wine ok(info.CommitSize == 0x10000, "Unexpected commit size %#Ix.\n", info.CommitSize); + ok(info.RegionSize == 0x10000, "Unexpected region size %#Ix.\n", info.RegionSize); + ok(info.CommitSize == 0x10000, "Unexpected commit size %#Ix.\n", info.CommitSize);
size = 0; status = NtFreeVirtualMemory(NtCurrentProcess(), &ptr, &size, MEM_RELEASE); @@ -2758,13 +2758,13 @@ static void test_query_region_information(void)
memset(&info, 0xcc, sizeof(info)); status = NtQueryVirtualMemory(NtCurrentProcess(), ptr, MemoryRegionInformation, &info, sizeof(info), &len); - todo_wine ok(status == STATUS_INVALID_ADDRESS, "Unexpected status %08lx.\n", status); - todo_wine ok(info.AllocationBase == (void *)(ULONG_PTR)0xcccccccccccccccc, "got %p.\n", info.AllocationBase); - todo_wine ok(info.AllocationProtect == 0xcccccccc, "Unexpected protection %lu.\n", info.AllocationProtect); - todo_wine ok(info.RegionType == 0xcccccccc, "got %#lx.\n", info.RegionType); + ok(status == STATUS_INVALID_ADDRESS, "Unexpected status %08lx.\n", status); + ok(info.AllocationBase == (void *)(ULONG_PTR)0xcccccccccccccccc, "got %p.\n", info.AllocationBase); + ok(info.AllocationProtect == 0xcccccccc, "Unexpected protection %lu.\n", info.AllocationProtect); + ok(info.RegionType == 0xcccccccc, "got %#lx.\n", info.RegionType);
/* Pagefile mapping */ - mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL); + mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 4096, NULL); ok(mapping != 0, "CreateFileMapping failed\n");
ptr = NULL; @@ -2785,7 +2785,7 @@ static void test_query_region_information(void) ok(!info.MappedPhysical, "Unexpected flag %d.\n", info.MappedPhysical); ok(!info.DirectMapped, "Unexpected flag %d.\n", info.DirectMapped); ok(info.RegionSize == 4096, "Unexpected region size.\n"); - todo_wine ok(!info.CommitSize, "Unexpected commit size %#Ix.\n", info.CommitSize); + ok(!info.CommitSize, "Unexpected commit size %#Ix.\n", info.CommitSize);
status = NtUnmapViewOfSection(NtCurrentProcess(), ptr); ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); @@ -2810,7 +2810,7 @@ static void test_query_region_information(void) ok(info.RegionSize == 4096, "Unexpected region size.\n"); ok(info.CommitSize == 4096, "Unexpected commit size %#Ix.\n", info.CommitSize);
- *(int *)ptr = 1; + *(volatile int *)ptr = 1; memset(&info, 0x11, sizeof(info)); status = NtQueryVirtualMemory(NtCurrentProcess(), ptr, MemoryRegionInformation, &info, sizeof(info), &len); ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); @@ -2833,6 +2833,7 @@ static void test_query_region_information(void) offset.QuadPart = 0; status = NtMapViewOfSection(mapping, NtCurrentProcess(), &ptr, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE); ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + *(volatile int *)ptr = 1;
memset(&info, 0x11, sizeof(info)); status = NtQueryVirtualMemory(NtCurrentProcess(), ptr, MemoryRegionInformation, &info, sizeof(info), &len); @@ -2846,7 +2847,7 @@ static void test_query_region_information(void) ok(!info.MappedPhysical, "Unexpected flag %d.\n", info.MappedPhysical); ok(!info.DirectMapped, "Unexpected flag %d.\n", info.DirectMapped); ok(info.RegionSize == 4096, "Unexpected region size.\n"); - todo_wine ok(!info.CommitSize, "Unexpected commit size %#Ix.\n", info.CommitSize); + ok(!info.CommitSize, "Unexpected commit size %#Ix.\n", info.CommitSize);
status = NtUnmapViewOfSection(NtCurrentProcess(), ptr); ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index a57da1b5d09..d4fc64235b6 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -5590,8 +5590,12 @@ static unsigned int get_basic_memory_info( HANDLE process, LPCVOID addr, static unsigned int get_memory_region_info( HANDLE process, LPCVOID addr, MEMORY_REGION_INFORMATION *info, SIZE_T len, SIZE_T *res_len ) { - MEMORY_BASIC_INFORMATION basic_info; - unsigned int status; + char *base, *region_start, *region_end; + struct file_view *view; + BYTE vprot, vprot_mask; + BOOL fake_reserved; + sigset_t sigset; + SIZE_T size;
if (len < FIELD_OFFSET(MEMORY_REGION_INFORMATION, CommitSize)) return STATUS_INFO_LENGTH_MISMATCH; @@ -5602,15 +5606,48 @@ static unsigned int get_memory_region_info( HANDLE process, LPCVOID addr, MEMORY return STATUS_NOT_IMPLEMENTED; }
- if ((status = fill_basic_memory_info( addr, &basic_info ))) return status; + base = ROUND_ADDR( addr, page_mask ); + + if (is_beyond_limit( base, 1, working_set_limit )) return STATUS_INVALID_PARAMETER; + + server_enter_uninterrupted_section( &virtual_mutex, &sigset ); + + if ((view = get_memory_region_size( base, ®ion_start, ®ion_end, &fake_reserved ))) + { + info->AllocationBase = view->base; + info->AllocationProtect = get_win32_prot( view->protect, view->protect ); + info->RegionType = 0; /* FIXME */ + if (len >= FIELD_OFFSET(MEMORY_REGION_INFORMATION, CommitSize)) + info->RegionSize = view->size; + if (len >= FIELD_OFFSET(MEMORY_REGION_INFORMATION, PartitionId)) + { + base = region_start; + info->CommitSize = 0; + vprot_mask = VPROT_COMMITTED; + if (!is_view_valloc( view )) vprot_mask |= PAGE_WRITECOPY; + while (base != region_end && + (size = get_committed_size( view, base, ~(size_t)0, &vprot, vprot_mask ))) + { + if ((vprot & vprot_mask) == vprot_mask) info->CommitSize += size; + base += size; + } + } + } + else + { + if (!fake_reserved) + { + server_leave_uninterrupted_section( &virtual_mutex, &sigset ); + return STATUS_INVALID_ADDRESS; + } + info->AllocationBase = region_start; + info->AllocationProtect = PAGE_NOACCESS; + info->RegionType = 0; /* FIXME */ + info->RegionSize = region_end - region_start; + info->CommitSize = 0; + }
- info->AllocationBase = basic_info.AllocationBase; - info->AllocationProtect = basic_info.AllocationProtect; - info->RegionType = 0; /* FIXME */ - if (len >= FIELD_OFFSET(MEMORY_REGION_INFORMATION, CommitSize)) - info->RegionSize = basic_info.RegionSize; - if (len >= FIELD_OFFSET(MEMORY_REGION_INFORMATION, PartitionId)) - info->CommitSize = basic_info.State == MEM_COMMIT ? basic_info.RegionSize : 0; + server_leave_uninterrupted_section( &virtual_mutex, &sigset );
if (res_len) *res_len = sizeof(*info); return STATUS_SUCCESS;
Turns out the CommitSize from MemoryBasicInformation was completely off too, that is also documented behaviour (https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/ns-memoryapi-w...) including the weirdness around taking into account PAGE_WRITECOPY file mappings only.
v3: - added tests for CommitSize; - Instead of trying to reuse fill_basic_memory_info() factor out the common part which gets region bounds and implement get_memory_region_info() separately.