core: Do not expand host mmap range during POSIX AddressSpace::Unmap (#5189)

Calling mmap(MAP_FIXED) over an expanded coalesced range and mutating *size causes issues:
- Calling mmap over already-free PROT_NONE memory adds redundant kernel overhead and risks Mach VM submap collisions on macOS.
- Mutating *size passes inflated ranges to callers like the GPU rasterizer.

Unmap strictly the requested [virtual_addr, virtual_addr + *size) range on the host, preserve *size, and remove unused m_free_regions from the POSIX implementation.
This commit is contained in:
Marcin Mitura authored and GitHub committed 2026-10-09 10:48:35 -07:00
1 parent e9f2c54c20
commit 437dc7eb8f
2 files changed
+9 -35

No files matched your search

+7 -30
View File
@@ -732,13 +732,6 @@ struct AddressSpace::Impl {
LOG_INFO(Kernel_Vmm, "User virtual memory region: {} - {}", fmt::ptr(user_base),
fmt::ptr(user_base + user_size - 1));
const VAddr system_managed_addr = reinterpret_cast<VAddr>(system_managed_base);
const VAddr system_reserved_addr = reinterpret_cast<VAddr>(system_reserved_base);
const VAddr user_addr = reinterpret_cast<VAddr>(user_base);
m_free_regions.insert({system_managed_addr, system_managed_addr + system_managed_size});
m_free_regions.insert({system_reserved_addr, system_reserved_addr + system_reserved_size});
m_free_regions.insert({user_addr, user_addr + user_size});
#ifdef __APPLE__
const auto shm_path = fmt::format("/BackingDmem{}", getpid());
backing_fd = shm_open(shm_path.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600);
@@ -781,7 +774,6 @@ struct AddressSpace::Impl {
void* Map(VAddr virtual_addr, PAddr phys_addr, u64 size, PosixPageProtection prot,
int fd = -1) {
m_free_regions.subtract({virtual_addr, virtual_addr + size});
#ifdef __APPLE__
if ((prot & PROT_EXEC) != 0) {
ASSERT_MSG(fd == -1, "Requested execute permissions for file mapping");
@@ -798,30 +790,16 @@ struct AddressSpace::Impl {
}
VAddr Unmap(VAddr virtual_addr, u64* size) {
// Check to see if we are adjacent to any regions.
VAddr start_address = virtual_addr;
VAddr end_address = start_address + *size;
ASSERT_MSG(size != nullptr && *size > 0, "Invalid unmap size");
// If we are, join with them, ensuring we stay in bounds.
auto it = m_free_regions.find({start_address - 1, end_address});
if (it != m_free_regions.end()) {
start_address = std::min(start_address, it->lower());
}
it = m_free_regions.find({start_address, end_address + 1});
if (it != m_free_regions.end()) {
end_address = std::max(end_address, it->upper());
}
// Free the relevant region.
m_free_regions.insert({start_address, end_address});
// Return the adjusted pointers.
void* ret = mmap(reinterpret_cast<void*>(start_address), end_address - start_address,
PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
int map_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
#if !defined(__FreeBSD__)
map_flags |= MAP_NORESERVE;
#endif
void* ret = mmap(reinterpret_cast<void*>(virtual_addr), *size, PROT_NONE, map_flags, -1, 0);
ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno));
*size = end_address - start_address;
return reinterpret_cast<VAddr>(ret);
return virtual_addr;
}
void Protect(VAddr virtual_addr, u64 size, bool read, bool write, bool execute) {
@@ -849,7 +827,6 @@ struct AddressSpace::Impl {
u64 system_reserved_size{};
u8* user_base{};
u64 user_size{};
boost::icl::interval_set<VAddr> m_free_regions;
};
#endif
+2 -5
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
@@ -91,10 +91,7 @@ public:
/// Memory maps a specified file descriptor.
void* MapFile(VAddr virtual_addr, u64 size, u64 offset, u32 prot, uintptr_t fd);
/// Unmaps specified virtual memory area.
/// Due to coalescing unmapped areas (implemented to save on VMAs), the real replaced area
/// might be different to what has been passed to Unmap. Therefore, a new address is returned
/// and size is updated to properly represent the mmapped area.
/// Unmaps specified virtual memory area and marks it free in the address space.
VAddr Unmap(VAddr virtual_addr, u64* size);
/// Protects requested region.