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
This commit is contained in:
Zephyron 2025-02-09 15:40:24 +10:00
parent becaf850ab
commit 5af4803e42
No known key found for this signature in database
2 changed files with 100 additions and 1 deletions

View file

@ -41,7 +41,23 @@ namespace Common {
constexpr size_t PageAlignment = 0x1000; constexpr size_t PageAlignment = 0x1000;
constexpr size_t HugePageSize = 0x200000; 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 #ifdef _WIN32
@ -763,6 +779,8 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
return; return;
} }
LogMemoryOperation("Map", virtual_offset, host_offset, length);
ASSERT(virtual_offset % PageAlignment == 0); ASSERT(virtual_offset % PageAlignment == 0);
ASSERT(length % PageAlignment == 0); ASSERT(length % PageAlignment == 0);
ASSERT(virtual_offset + length <= virtual_size); 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; 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); impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms);
} }
void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap) { 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(virtual_offset % PageAlignment == 0);
ASSERT(length % PageAlignment == 0); ASSERT(length % PageAlignment == 0);
ASSERT(virtual_offset + length <= virtual_size); ASSERT(virtual_offset + length <= virtual_size);
if (length == 0 || !virtual_base || !impl) { if (length == 0 || !virtual_base || !impl) {
return; 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 } // namespace Common

View file

@ -52,6 +52,13 @@ public:
void ClearBackingRegion(size_t physical_offset, size_t length, u32 fill_value); 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 { [[nodiscard]] u8* BackingBasePointer() noexcept {
return backing_base; return backing_base;
} }