Merge pull request #778 from PatrickvL/MemoryManagerFix

MemoryManager : Fixed block-lookup with non-base addresses, by using …
This commit is contained in:
Luke Usher 2017-10-27 13:21:52 +01:00 committed by GitHub
commit 6a705276b7
2 changed files with 20 additions and 24 deletions

View File

@ -54,22 +54,21 @@ MemoryManager::~MemoryManager()
DeleteCriticalSection(&m_CriticalSection); DeleteCriticalSection(&m_CriticalSection);
} }
// Acquire m_CriticalSection before calling FindContainingTypedMemoryBlock!
TypedMemoryBlock *MemoryManager::FindContainingTypedMemoryBlock(void* addr) TypedMemoryBlock *MemoryManager::FindContainingTypedMemoryBlock(void* addr)
{ {
if (m_MemoryBlockInfo.empty()) // Find the first block whose key (upper_bound) is not less than the requested address (thus: upper_bound >= addr)
return nullptr;
// Find the first block whose address is not less than the requested address
auto low = m_MemoryBlockInfo.lower_bound(addr); auto low = m_MemoryBlockInfo.lower_bound(addr);
if (low == m_MemoryBlockInfo.end()) if (low == m_MemoryBlockInfo.end())
// If there's no such block, it might fall into the last block return nullptr;
low = --m_MemoryBlockInfo.end();
// Check if the requested address lies inside this block // Check if the requested address lies inside this block
TypedMemoryBlock *info = &(low->second); TypedMemoryBlock *info = &(low->second);
if ((size_t)addr >= ((size_t)info->block.addr + info->block.size)) if (addr < info->block.addr)
return nullptr; return nullptr;
assert((uintptr_t)addr <= ((uintptr_t)info->block.upper_bound));
return info; return info;
} }
@ -85,11 +84,10 @@ void* MemoryManager::Allocate(size_t size)
TypedMemoryBlock info; TypedMemoryBlock info;
info.type = MemoryType::STANDARD; info.type = MemoryType::STANDARD;
info.block.addr = addr; info.block.init(addr, size);
info.block.size = size;
EnterCriticalSection(&m_CriticalSection); EnterCriticalSection(&m_CriticalSection);
m_MemoryBlockInfo[addr] = info; m_MemoryBlockInfo[info.block.upper_bound] = info;
LeaveCriticalSection(&m_CriticalSection); LeaveCriticalSection(&m_CriticalSection);
} else { } else {
#if 1 // TODO : Only log this in DEBUG builds (as a failure is already indicated by a null result) #if 1 // TODO : Only log this in DEBUG builds (as a failure is already indicated by a null result)
@ -115,11 +113,10 @@ void* MemoryManager::AllocateAligned(size_t size, size_t alignment)
TypedMemoryBlock info; TypedMemoryBlock info;
info.type = MemoryType::ALIGNED; info.type = MemoryType::ALIGNED;
info.block.addr = addr; info.block.init(addr, size);
info.block.size = size;
EnterCriticalSection(&m_CriticalSection); EnterCriticalSection(&m_CriticalSection);
m_MemoryBlockInfo[addr] = info; m_MemoryBlockInfo[info.block.upper_bound] = info;
LeaveCriticalSection(&m_CriticalSection); LeaveCriticalSection(&m_CriticalSection);
} }
@ -143,7 +140,7 @@ void* MemoryManager::AllocateContiguous(size_t size, size_t alignment)
EnterCriticalSection(&m_CriticalSection); EnterCriticalSection(&m_CriticalSection);
// Is the contiguous allocation table empty? // Is the contiguous allocation table empty?
if (m_ContiguousMemoryBlocks.size() == 0) { if (m_ContiguousMemoryBlocks.empty()) {
// Start allocating Contiguous Memory after the Kernel image header to prevent overwriting our dummy Kernel // Start allocating Contiguous Memory after the Kernel image header to prevent overwriting our dummy Kernel
addr = XBOX_KERNEL_BASE + sizeof(DUMMY_KERNEL); addr = XBOX_KERNEL_BASE + sizeof(DUMMY_KERNEL);
addr = (addr + alignMask) & ~alignMask; addr = (addr + alignMask) & ~alignMask;
@ -153,7 +150,7 @@ void* MemoryManager::AllocateContiguous(size_t size, size_t alignment)
// in order to reduce memory fragmentation. // in order to reduce memory fragmentation.
for (auto it = m_ContiguousMemoryBlocks.begin(); it != m_ContiguousMemoryBlocks.end(); ++it) { for (auto it = m_ContiguousMemoryBlocks.begin(); it != m_ContiguousMemoryBlocks.end(); ++it) {
MemoryBlock current = it->second; MemoryBlock current = it->second;
xbaddr after_current = (xbaddr)current.addr + current.size; xbaddr after_current = (xbaddr)current.upper_bound + 1;
after_current = (after_current + alignMask) & ~alignMask; after_current = (after_current + alignMask) & ~alignMask;
// Is this the last entry? // Is this the last entry?
@ -183,8 +180,7 @@ void* MemoryManager::AllocateContiguous(size_t size, size_t alignment)
if (addr != NULL) { if (addr != NULL) {
MemoryBlock block; MemoryBlock block;
block.addr = (void *)addr; block.init((void *)addr, size);
block.size = size;
m_ContiguousMemoryBlocks[(void *)addr] = block; m_ContiguousMemoryBlocks[(void *)addr] = block;
TypedMemoryBlock info; TypedMemoryBlock info;
@ -192,7 +188,7 @@ void* MemoryManager::AllocateContiguous(size_t size, size_t alignment)
info.type = MemoryType::CONTIGUOUS; info.type = MemoryType::CONTIGUOUS;
info.block = block; info.block = block;
m_MemoryBlockInfo[(void *)addr] = info; m_MemoryBlockInfo[info.block.upper_bound] = info;
} }
LeaveCriticalSection(&m_CriticalSection); LeaveCriticalSection(&m_CriticalSection);
@ -238,20 +234,19 @@ void MemoryManager::Free(void* addr)
switch (info->type) { switch (info->type) {
case MemoryType::ALIGNED: case MemoryType::ALIGNED:
_aligned_free((void*)info->block.addr); _aligned_free((void*)info->block.addr);
m_MemoryBlockInfo.erase(info->block.addr);
break; break;
case MemoryType::STANDARD: case MemoryType::STANDARD:
free((void*)info->block.addr); free((void*)info->block.addr);
m_MemoryBlockInfo.erase(info->block.addr);
break; break;
case MemoryType::CONTIGUOUS: case MemoryType::CONTIGUOUS:
m_ContiguousMemoryBlocks.erase(info->block.addr); m_ContiguousMemoryBlocks.erase(info->block.addr);
m_MemoryBlockInfo.erase(info->block.addr);
break; break;
default: default:
CxbxKrnlCleanup("Fatal: MemoryManager attempted to free memory of an unknown type"); CxbxKrnlCleanup("Fatal: MemoryManager attempted to free memory of an unknown type");
break; break;
} }
m_MemoryBlockInfo.erase(info->block.upper_bound);
} }
else { else {
__debugbreak(); __debugbreak();
@ -274,8 +269,8 @@ size_t MemoryManager::QueryAllocationSize(void* addr)
EnterCriticalSection(&m_CriticalSection); EnterCriticalSection(&m_CriticalSection);
TypedMemoryBlock *info = FindContainingTypedMemoryBlock(addr); TypedMemoryBlock *info = FindContainingTypedMemoryBlock(addr);
if (info != nullptr) { if (info != nullptr) {
// Return the total size in this block // Return the available size in this block
ret = info->block.size - ((size_t)addr - (size_t)info->block.addr); ret = (uintptr_t)info->block.upper_bound - (uintptr_t)addr + 1;
} }
else { else {
#if 1 // TODO : Only log this in DEBUG builds (as a failure is already indicated by a null result)? #if 1 // TODO : Only log this in DEBUG builds (as a failure is already indicated by a null result)?

View File

@ -44,7 +44,8 @@
typedef struct { typedef struct {
void *addr; void *addr;
size_t size; void *upper_bound;
void init(void * base, size_t size) { addr = base; upper_bound = (void *)((uintptr_t)base + size - 1); }
} MemoryBlock; } MemoryBlock;
enum struct MemoryType { enum struct MemoryType {