From 5af4803e42f206d6332e812997e5db45ea01d0b5 Mon Sep 17 00:00:00 2001 From: Zephyron Date: Sun, 9 Feb 2025 15:40:24 +1000 Subject: [PATCH] common: Enhance memory mapping safety and debugging - Reduce max_memory_size from 512GB to 1GB for safer allocation limits - Add memory operation logging for debugging purposes - Implement MapMemory() with additional safety checks and large allocation handling - Add validation checks for memory mappings - Introduce chunked allocation strategy for large memory requests - Add detailed error logging for memory operations --- src/common/host_memory.cpp | 94 +++++++++++++++++++++++++++++++++++++- src/common/host_memory.h | 7 +++ 2 files changed, 100 insertions(+), 1 deletion(-) diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 0678efa50..551d2838a 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -41,7 +41,23 @@ namespace Common { constexpr size_t PageAlignment = 0x1000; constexpr size_t HugePageSize = 0x200000; -constexpr size_t max_memory_size = 0x8000000000; // 512 GB max memory size +constexpr size_t max_memory_size = 0x40000000; // 1GB max memory size +constexpr bool ENABLE_MEMORY_DEBUG = true; + +// Move LogMemoryOperation declaration to the top, before any usage +static void LogMemoryOperation(const char* operation, size_t virtual_offset, size_t host_offset, + size_t length, const char* result = nullptr) { + if (!ENABLE_MEMORY_DEBUG) { + return; + } + if (result) { + LOG_DEBUG(Common_Memory, "{}: virtual=0x{:x}, host=0x{:x}, length=0x{:x} ({})", + operation, virtual_offset, host_offset, length, result); + } else { + LOG_DEBUG(Common_Memory, "{}: virtual=0x{:x}, host=0x{:x}, length=0x{:x}", + operation, virtual_offset, host_offset, length); + } +} #ifdef _WIN32 @@ -763,6 +779,8 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length, return; } + LogMemoryOperation("Map", virtual_offset, host_offset, length); + ASSERT(virtual_offset % PageAlignment == 0); ASSERT(length % PageAlignment == 0); ASSERT(virtual_offset + length <= virtual_size); @@ -771,13 +789,24 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length, return; } + // Check if mapping is valid + if (!impl->IsValidMapping(host_offset, length)) { + LOG_WARNING(Common_Memory, + "Memory validation failed: virtual=0x{:x}, host=0x{:x}, length=0x{:x}", + virtual_offset, host_offset, length); + // Continue anyway - the mapping may still work + } + impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms); } void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap) { + LogMemoryOperation("Unmap", virtual_offset, 0, length); + ASSERT(virtual_offset % PageAlignment == 0); ASSERT(length % PageAlignment == 0); ASSERT(virtual_offset + length <= virtual_size); + if (length == 0 || !virtual_base || !impl) { return; } @@ -819,4 +848,67 @@ void HostMemory::EnableDirectMappedAddress() { } } +bool HostMemory::MapMemory(uint64_t virtual_offset, uint64_t host_offset, uint64_t length) { + static constexpr uint64_t MAX_SAFE_ALLOCATION = 0x40000000; // 1GB max allocation + + if (!impl || !impl->IsValidMapping(host_offset, length)) { + // For very large allocations, try splitting into smaller chunks + if (length > MAX_SAFE_ALLOCATION) { + LOG_WARNING(Common_Memory, + "Large mapping requested: virtual=0x{:x}, host=0x{:x}, size=0x{:x}. Attempting split allocation.", + virtual_offset, host_offset, length); + + // Try mapping in smaller chunks + uint64_t remaining = length; + uint64_t current_virtual = virtual_offset; + uint64_t current_host = host_offset; + + while (remaining > 0) { + uint64_t chunk_size = std::min(remaining, MAX_SAFE_ALLOCATION); + if (!MapMemory(current_virtual, current_host, chunk_size)) { + LOG_ERROR(Common_Memory, + "Failed to map memory chunk: virtual=0x{:x}, host=0x{:x}, size=0x{:x}", + current_virtual, current_host, chunk_size); + return false; + } + remaining -= chunk_size; + current_virtual += chunk_size; + current_host += chunk_size; + } + return true; + } + + LOG_ERROR(Common_Memory, + "Failed to verify memory mapping: virtual_offset=0x{:x}, host_offset=0x{:x}, length=0x{:x}", + virtual_offset, host_offset, length); + return false; + } + + // Ensure addresses are page-aligned + if ((virtual_offset & (PageAlignment - 1)) || (host_offset & (PageAlignment - 1))) { + LOG_ERROR(Common_Memory, + "Unaligned memory mapping: virtual=0x{:x}, host=0x{:x}", + virtual_offset, host_offset); + return false; + } + + try { + // Add the missing separate_heap parameter + Map(virtual_offset, host_offset, length, MemoryPermission::ReadWrite, false); + + if (ENABLE_MEMORY_DEBUG) { + LOG_DEBUG(Common_Memory, + "Successfully mapped memory: virtual=0x{:x}, host=0x{:x}, length=0x{:x}", + virtual_offset, host_offset, length); + } + + return true; + } catch (const std::exception& e) { + LOG_ERROR(Common_Memory, + "Failed to map memory: virtual=0x{:x}, host=0x{:x}, length=0x{:x}, error: {}", + virtual_offset, host_offset, length, e.what()); + return false; + } +} + } // namespace Common diff --git a/src/common/host_memory.h b/src/common/host_memory.h index 7d4a94123..438edd659 100644 --- a/src/common/host_memory.h +++ b/src/common/host_memory.h @@ -52,6 +52,13 @@ public: void ClearBackingRegion(size_t physical_offset, size_t length, u32 fill_value); + /// Attempts to map memory with additional safety checks and chunking for large allocations + /// @param virtual_offset The virtual memory address to map to + /// @param host_offset The physical memory address to map from + /// @param length The size of the mapping in bytes + /// @return true if mapping succeeded, false if it failed + bool MapMemory(uint64_t virtual_offset, uint64_t host_offset, uint64_t length); + [[nodiscard]] u8* BackingBasePointer() noexcept { return backing_base; }