In get_valloc_info, if mem happens to point to the last chunk of memory in the user space virtual address space, "p += info2.RegionSize" will cause it to go over the limit, and subsequent VirtualQueries will fail, thus info2 won't be changed, thus the loop exit condition is never met (well until p wraps around, that is).
* * *
Witnessed this in CI:
``` 012c:0130:trace:virtual:NtQueryVirtualMemory (0xffffffffffffffff, 0x7ffffffe0000, info_class=0, 0x442120, 48, 0xfd4a0) 012c:0130:trace:virtual:get_vprot_range_size base 0x7ffffffe0000, size 0x10000, mask 0xbf. 012c:0130:trace:virtual:NtQueryVirtualMemory (0xffffffffffffffff, 0x7ffffffe0000, info_class=0, 0x442170, 48, 0xfd520) 012c:0130:trace:virtual:get_vprot_range_size base 0x7ffffffe0000, size 0x10000, mask 0xbf. 012c:0130:trace:virtual:NtQueryVirtualMemory (0xffffffffffffffff, 0x7fffffff0000, info_class=0, 0x442170, 48, 0xfd5e0) 012c:0130:trace:virtual:NtQueryVirtualMemory (0xffffffffffffffff, 0x800000000000, info_class=0, 0x442170, 48, 0xfd820) 012c:0130:trace:virtual:NtQueryVirtualMemory (0xffffffffffffffff, 0x800000010000, info_class=0, 0x442170, 48, 0xfda60) 012c:0130:trace:virtual:NtQueryVirtualMemory (0xffffffffffffffff, 0x800000020000, info_class=0, 0x442170, 48, 0xfdca0) 012c:0130:trace:virtual:NtQueryVirtualMemory (0xffffffffffffffff, 0x800000030000, info_class=0, 0x442170, 48, 0xfdee0) ... ```
and winetest logs:
``` ... heap.c:3662:3.322 Test failed: init size 0: got 0. heap.c:3662:3.322 Test failed: init size 0: got 0. heap.c:3662:3.322 Test failed: init size 0: got 0. heap.c:3662:3.322 Test failed: init size 0: got 0. heap.c:3662:3.322 Test failed: init size 0: got 0. heap.c:3662:3.322 Test failed: init size 0: got 0. heap.c:3662:3.323 Test failed: init size 0: got 0. heap.c:3662:3.323 Test failed: init size 0: got 0. ... ```
ad infinitum
Probably made more likely by ASan since it takes a big chunk of the address space.
From: Yuxuan Shui yshui@codeweavers.com
In get_valloc_info, if mem happens to point to the last chunk of memory in the user space virtual address space, "p += info2.RegionSize" will cause it to go over the limit, and subsequent VirtualQueries will fail, thus info2 won't be changed, thus the loop exit condition is never met (well until p wraps around, that is). --- dlls/kernel32/tests/heap.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index f88a140a115..ec3549ac605 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -3648,15 +3648,20 @@ static void test_GlobalMemoryStatus(void) static void get_valloc_info( void *mem, char **base, SIZE_T *alloc_size ) { MEMORY_BASIC_INFORMATION info, info2; + SYSTEM_BASIC_INFORMATION si; + NTSTATUS status; SIZE_T size; char *p;
+ status = NtQuerySystemInformation(SystemBasicInformation, &si, sizeof(si), NULL); + ok( !status, "NtQuerySystemInformation returned %#lx\n", status ); + size = VirtualQuery( mem, &info, sizeof(info) ); ok( size == sizeof(info), "got %Iu.\n", size );
info2 = info; p = info.AllocationBase; - while (1) + while (p < (char *)si.HighestUserAddress) { size = VirtualQuery( p, &info2, sizeof(info2) ); ok( size == sizeof(info), "got %Iu.\n", size );