From bf6e1a81eb22ee0866978cd812f2adf3a83a1593 Mon Sep 17 00:00:00 2001 From: "Herman S." <429230+has207@users.noreply.github.com> Date: Sun, 15 Feb 2026 14:37:28 +0900 Subject: [PATCH] [Posix] Fix DeallocFixed crashes / memory leaks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BaseHeap::Dispose() walks the page table and calls DeallocFixed(addr, 0, kRelease) for every allocated page region. These addresses are within file-backed view mappings (i.e. guest memory). On Windows, VirtualFree on file-mapped pages silently returns FALSE. On POSIX, the code hit assert_always() and crashed. Changed to return false to match Windows behavior. Memory leaks from munmap(addr, 0): Callers passed length=0 to DeallocFixed(kRelease). On Windows this works because VirtualFree(addr, 0, MEM_RELEASE) means "release the entire region" — Windows ignores the length parameter for MEM_RELEASE and always frees the whole allocation. On POSIX, munmap(addr, 0) fails with EINVAL, so the memory was silently leaked every time. --- src/xenia/base/memory_posix.cc | 2 +- src/xenia/cpu/backend/x64/x64_code_cache.cc | 2 +- src/xenia/cpu/backend/x64/x64_emitter.cc | 3 ++- src/xenia/cpu/thread_state.cc | 7 ++++--- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/xenia/base/memory_posix.cc b/src/xenia/base/memory_posix.cc index bb14fc583..15a9ab858 100644 --- a/src/xenia/base/memory_posix.cc +++ b/src/xenia/base/memory_posix.cc @@ -171,7 +171,7 @@ bool DeallocFixed(void* base_address, size_t length, case DeallocationType::kDecommit: return Protect(base_address, length, PageAccess::kNoAccess); case DeallocationType::kRelease: - assert_always("Error: Tried to release mapped memory!"); + return false; default: assert_unhandled_case(deallocation_type); } diff --git a/src/xenia/cpu/backend/x64/x64_code_cache.cc b/src/xenia/cpu/backend/x64/x64_code_cache.cc index b63127c6f..c386d15ca 100644 --- a/src/xenia/cpu/backend/x64/x64_code_cache.cc +++ b/src/xenia/cpu/backend/x64/x64_code_cache.cc @@ -38,7 +38,7 @@ X64CodeCache::X64CodeCache() = default; X64CodeCache::~X64CodeCache() { if (indirection_table_base_) { - xe::memory::DeallocFixed(indirection_table_base_, 0, + xe::memory::DeallocFixed(indirection_table_base_, kIndirectionTableSize, xe::memory::DeallocationType::kRelease); } diff --git a/src/xenia/cpu/backend/x64/x64_emitter.cc b/src/xenia/cpu/backend/x64/x64_emitter.cc index 5262d0a4f..51e9847fd 100644 --- a/src/xenia/cpu/backend/x64/x64_emitter.cc +++ b/src/xenia/cpu/backend/x64/x64_emitter.cc @@ -1291,7 +1291,8 @@ uintptr_t X64Emitter::PlaceConstData() { } void X64Emitter::FreeConstData(uintptr_t data) { - memory::DeallocFixed(reinterpret_cast(data), 0, + memory::DeallocFixed(reinterpret_cast(data), + xe::round_up(kConstDataSize, memory::page_size()), memory::DeallocationType::kRelease); } diff --git a/src/xenia/cpu/thread_state.cc b/src/xenia/cpu/thread_state.cc index bc1315887..fc16b5a1c 100644 --- a/src/xenia/cpu/thread_state.cc +++ b/src/xenia/cpu/thread_state.cc @@ -56,9 +56,10 @@ static void* AllocateContext() { } static void FreeContext(void* ctx) { - char* true_start_of_ctx = &reinterpret_cast( - ctx)[-static_cast(xe::memory::allocation_granularity())]; - memory::DeallocFixed(true_start_of_ctx, 0, + size_t granularity = xe::memory::allocation_granularity(); + char* true_start_of_ctx = + &reinterpret_cast(ctx)[-static_cast(granularity)]; + memory::DeallocFixed(true_start_of_ctx, granularity + sizeof(ppc::PPCContext), memory::DeallocationType::kRelease); }