From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/unix/virtual.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 3981905bcd3..0c38c57f653 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -4998,6 +4998,7 @@ static unsigned int fill_basic_memory_info( const void *addr, MEMORY_BASIC_INFOR * so that the app doesn't believe it's fully available */ { struct reserved_area *area; + BOOL in_reserved = FALSE;
LIST_FOR_EACH_ENTRY( area, &reserved_areas, struct reserved_area, entry ) { @@ -5012,6 +5013,7 @@ static unsigned int fill_basic_memory_info( const void *addr, MEMORY_BASIC_INFOR if (area_start <= base || area_start <= (char *)address_space_start) { 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 */ @@ -5022,18 +5024,22 @@ static unsigned int fill_basic_memory_info( const void *addr, MEMORY_BASIC_INFOR if (base < next) { info->RegionSize = min( next, alloc_end ) - base; + in_reserved = TRUE; break; } else alloc_base = base; } /* 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; - break; } } #endif
Bionic Commando regressed (doesn't start) after the change introduced in commit 800fc4164f9d4ef4af23c2249b5c8ee92f48c673 ("ntdll: Reimplement fill_basic_memory_info() without using a callback."). Before that commit the space which is completely outside of reserved area were reported as allocated. Now it is reported as free. The game uses the following algorithm to determine its internal memory allocation size and does not expect the allocation to fail: ``` void *allocate() { MEMORY_BASIC_INFORMATION i; SYSTEM_INFO si; SIZE_T max_size = 0;
GetSystemInfo(&si); for (addr = si.lpMinimumApplicationAddress; VirtualQuery(addr, &i, sizeof(i)) == sizeof(i); addr += i.RegionSize) { if (i.State != MEM_FREE) continue; if (i.RegionSize > max_size) max_size = i.RegionSize; } max_size &= 0xfff00000; max_size = max(max_size, 0x10000000); return VirtualAlloc(NULL, max_size, MEM_RESERVE, PAGE_READWRITE); } ```
The game has Large address aware flag set on executable. So now this algorithm finds the size of 0x7fe00000 in the upper 2GB. This size cannot be allocated, first because an extra 64k requested in map_view() to perform proper alignment and next because the space is not free really, there are Unix side allocated areas which are out of our control.
It is probably not ideal to report the whole high 2GB as allocated, but so Far I didn't find an obviously better way to avoid such issues and fix the regression.