From 463686d01a0bad49d0ad8d9a9e3d5f1e8697b606 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Tue, 4 Nov 2025 00:15:26 -0700 Subject: [PATCH] GlobalAlloc: Add VirtualAlloc fallback for large sizes --- dll/kernel32/winbase.cpp | 80 +++++++++++++++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 9 deletions(-) diff --git a/dll/kernel32/winbase.cpp b/dll/kernel32/winbase.cpp index 9130aff..e8f9e78 100644 --- a/dll/kernel32/winbase.cpp +++ b/dll/kernel32/winbase.cpp @@ -6,6 +6,7 @@ #include "files.h" #include "heap.h" #include "internal.h" +#include "mimalloc/types.h" #include "modules.h" #include "strutil.h" #include "types.h" @@ -170,9 +171,23 @@ void *doAlloc(UINT dwBytes, bool zero) { if (dwBytes == 0) { dwBytes = 1; } - void *ret = mi_heap_malloc_aligned(wibo::heap::getGuestHeap(), dwBytes, 8); + void *ret; + size_t size = static_cast(dwBytes); + if (dwBytes > MI_ARENA_MAX_OBJ_SIZE) { + // If the size is too large, allocate memory using virtualAlloc + DEBUG_LOG("doAlloc(%u, %d) -> virtualAlloc\n", dwBytes, zero); + void *addr = nullptr; + const auto result = wibo::heap::virtualAlloc(&addr, &size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + if (result != wibo::heap::VmStatus::Success) { + return nullptr; + } + ret = addr; + } else { + ret = mi_heap_malloc_aligned(wibo::heap::getGuestHeap(), dwBytes, 8); + size = mi_usable_size(ret); + } if (ret && zero) { - std::memset(ret, 0, mi_usable_size(ret)); + std::memset(ret, 0, size); } return ret; } @@ -181,15 +196,53 @@ void *doRealloc(void *mem, UINT dwBytes, bool zero) { if (dwBytes == 0) { dwBytes = 1; } - size_t oldSize = mi_usable_size(mem); - void *ret = mi_heap_realloc_aligned(wibo::heap::getGuestHeap(), mem, dwBytes, 8); - size_t newSize = mi_usable_size(ret); + size_t oldSize; + void *ret; + size_t newSize = static_cast(dwBytes); + mi_heap_t *heap = wibo::heap::getGuestHeap(); + if ((mem == nullptr && dwBytes <= MI_ARENA_MAX_OBJ_SIZE) || mi_is_in_heap_region(mem)) { + oldSize = mi_usable_size(mem); + ret = mi_heap_realloc_aligned(heap, mem, dwBytes, 8); + newSize = mi_usable_size(ret); + } else { + DEBUG_LOG("doRealloc(%u, %d, %d) -> virtualAlloc\n", dwBytes, zero, mem); + MEMORY_BASIC_INFORMATION info; + auto result = wibo::heap::virtualQuery(mem, &info); + if (result != wibo::heap::VmStatus::Success) { + return nullptr; + } + oldSize = info.RegionSize; + result = wibo::heap::virtualAlloc(&ret, &newSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + if (result != wibo::heap::VmStatus::Success) { + return nullptr; + } + std::memcpy(ret, mem, oldSize); + wibo::heap::virtualFree(mem, oldSize, MEM_RELEASE); + } if (ret && zero && newSize > oldSize) { std::memset(static_cast(ret) + oldSize, 0, newSize - oldSize); } return ret; } +bool doFree(void *mem) { + if (mem == nullptr) { + return false; + } + if (mi_is_in_heap_region(mem)) { + mi_free(mem); + } else { + DEBUG_LOG("doFree(%p) -> virtualFree\n", mem); + MEMORY_BASIC_INFORMATION info; + auto result = wibo::heap::virtualQuery(mem, &info); + if (result != wibo::heap::VmStatus::Success || info.BaseAddress != mem) { + return false; + } + wibo::heap::virtualFree(mem, info.RegionSize, MEM_RELEASE); + } + return true; +} + bool tryGetCurrentDirectoryPath(std::string &outPath) { std::error_code ec; std::filesystem::path cwd = std::filesystem::current_path(ec); @@ -755,14 +808,21 @@ HGLOBAL WINAPI GlobalAlloc(UINT uFlags, SIZE_T dwBytes) { return nullptr; } bool zero = (uFlags & GMEM_ZEROINIT) != 0; - return doAlloc(static_cast(dwBytes), zero); + void *ret = doAlloc(static_cast(dwBytes), zero); + DEBUG_LOG("-> %p\n", ret); + return ret; } HGLOBAL WINAPI GlobalFree(HGLOBAL hMem) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("GlobalFree(%p)\n", hMem); - std::free(hMem); - return nullptr; + if (doFree(hMem)) { + DEBUG_LOG("-> success\n"); + return nullptr; + } else { + DEBUG_LOG("-> failure\n"); + return hMem; + } } HGLOBAL WINAPI GlobalReAlloc(HGLOBAL hMem, SIZE_T dwBytes, UINT uFlags) { @@ -773,7 +833,9 @@ HGLOBAL WINAPI GlobalReAlloc(HGLOBAL hMem, SIZE_T dwBytes, UINT uFlags) { return nullptr; } bool zero = (uFlags & GMEM_ZEROINIT) != 0; - return doRealloc(hMem, static_cast(dwBytes), zero); + void *ret = doRealloc(hMem, static_cast(dwBytes), zero); + DEBUG_LOG("-> %p\n", ret); + return ret; } UINT WINAPI GlobalFlags(HGLOBAL hMem) {