1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +02:00

Fixed heap bugs - mostly a major leak

This commit is contained in:
Brian Fiete 2021-11-26 17:59:58 -08:00
parent 4de601be57
commit ec61583db8
2 changed files with 188 additions and 16 deletions

View file

@ -1,5 +1,6 @@
#include "Heap.h" #include "Heap.h"
#include "DLIList.h" #include "DLIList.h"
#include "HashSet.h"
USING_NS_BF; USING_NS_BF;
@ -129,21 +130,33 @@ ContiguousHeap::~ContiguousHeap()
free(mMetadata); free(mMetadata);
} }
//#define BFCE_DEBUG_HEAP
void ContiguousHeap::Clear(int maxAllocSize) void ContiguousHeap::Clear(int maxAllocSize)
{ {
#ifdef BFCE_DEBUG_HEAP
OutputDebugStrF("ContiguousHeap::Clear\n");
#endif
if (mBlockDataOfs == 0) if (mBlockDataOfs == 0)
return; return;
mBlockDataOfs = 0;
mFreeList.Clear();
if ((mMemorySize != -1) && (mMemorySize > maxAllocSize)) if ((mMemorySize != -1) && (mMemorySize > maxAllocSize))
{ {
free(mMetadata); free(mMetadata);
mMetadata = NULL; mMetadata = NULL;
mMemorySize = 0; mMemorySize = 0;
mBlockDataOfs = 0;
mFreeList.Clear();
return; return;
} }
for (auto idx : mFreeList)
{
auto block = CH_REL_TO_ABS(idx);
block->mKind = (ChBlockKind)0;
}
auto blockList = (ChList*)mMetadata; auto blockList = (ChList*)mMetadata;
if (blockList->mHead != -1) if (blockList->mHead != -1)
{ {
@ -156,18 +169,29 @@ void ContiguousHeap::Clear(int maxAllocSize)
block = CH_REL_TO_ABS(block->mNext); block = CH_REL_TO_ABS(block->mNext);
} }
} }
blockList->mHead = -1; blockList->mHead = -1;
blockList->mTail = -1; blockList->mTail = -1;
mBlockDataOfs = 0;
mFreeList.Clear();
Validate();
} }
//static int gAllocCount = 0; static int gAllocCount = 0;
ContiguousHeap::AllocRef ContiguousHeap::Alloc(int size) ContiguousHeap::AllocRef ContiguousHeap::Alloc(int size)
{ {
if (size == 0) if (size == 0)
return 0; return 0;
//int allocCount = ++gAllocCount; #ifdef BFCE_DEBUG_HEAP
int allocCount = ++gAllocCount;
if (allocCount == 358)
{
NOP;
}
#endif
size = BF_ALIGN(size, 16); size = BF_ALIGN(size, 16);
@ -183,7 +207,9 @@ ContiguousHeap::AllocRef ContiguousHeap::Alloc(int size)
if (block->mKind == ChBlockKind_Merged) if (block->mKind == ChBlockKind_Merged)
{ {
//OutputDebugStrF("ContiguousHeap::Alloc %d removing merged %d\n", allocCount, (uint8*)block - (uint8*)mMetadata); #ifdef BFCE_DEBUG_HEAP
OutputDebugStrF("ContiguousHeap::Alloc %d removing merged %d\n", allocCount, (uint8*)block - (uint8*)mMetadata);
#endif
itr--; itr--;
block->mKind = (ChBlockKind)0; block->mKind = (ChBlockKind)0;
@ -211,6 +237,9 @@ ContiguousHeap::AllocRef ContiguousHeap::Alloc(int size)
else else
{ {
BF_ASSERT(newBlock->mKind == ChBlockKind_Merged); BF_ASSERT(newBlock->mKind == ChBlockKind_Merged);
#ifdef BFCE_DEBUG_HEAP
BF_ASSERT(mFreeList.Contains(CH_ABS_TO_REL(newBlock)));
#endif
} }
newBlock->mPrev = -1; newBlock->mPrev = -1;
newBlock->mNext = -1; newBlock->mNext = -1;
@ -219,10 +248,23 @@ ContiguousHeap::AllocRef ContiguousHeap::Alloc(int size)
blockList->AddAfter(CH_ABS_TO_REL(block), CH_ABS_TO_REL(newBlock)); blockList->AddAfter(CH_ABS_TO_REL(block), CH_ABS_TO_REL(newBlock));
block->mSize = size; block->mSize = size;
//OutputDebugStrF("ContiguousHeap::Alloc %d alloc %d size: %d remainder in %d size: %d\n", allocCount, CH_ABS_TO_REL(block), size, CH_ABS_TO_REL(newBlock), newBlock->mSize); #ifdef BFCE_DEBUG_HEAP
OutputDebugStrF("ContiguousHeap::Alloc %d alloc %d size: %d remainder in %d size: %d\n", allocCount, CH_ABS_TO_REL(block), size, CH_ABS_TO_REL(newBlock), newBlock->mSize);
#endif
}
else
{
#ifdef BFCE_DEBUG_HEAP
OutputDebugStrF("ContiguousHeap::Alloc %d alloc %d size: %d\n", allocCount, CH_ABS_TO_REL(block), size);
#endif
} }
block->mKind = ChBlockKind_Used; block->mKind = ChBlockKind_Used;
#ifdef BFCE_DEBUG_HEAP
Validate();
#endif
return CH_ABS_TO_REL(block); return CH_ABS_TO_REL(block);
} }
@ -255,7 +297,10 @@ ContiguousHeap::AllocRef ContiguousHeap::Alloc(int size)
mFreeList.Add(CH_ABS_TO_REL(block)); mFreeList.Add(CH_ABS_TO_REL(block));
//OutputDebugStrF("ContiguousHeap::Alloc %d alloc %d size: %d\n", allocCount, (uint8*)block - (uint8*)mMetadata, block->mSize); #ifdef BFCE_DEBUG_HEAP
Validate();
OutputDebugStrF("ContiguousHeap::Alloc %d alloc %d size: %d\n", allocCount, (uint8*)block - (uint8*)mMetadata, block->mSize);
#endif
if (mFreeIdx >= mFreeList.mSize) if (mFreeIdx >= mFreeList.mSize)
mFreeIdx = 0; mFreeIdx = 0;
@ -267,11 +312,29 @@ bool ContiguousHeap::Free(AllocRef ref)
if ((ref < 0) || (ref > mMemorySize - sizeof(ChBlock))) if ((ref < 0) || (ref > mMemorySize - sizeof(ChBlock)))
return false; return false;
#ifdef BFCE_DEBUG_HEAP
int allocCount = ++gAllocCount;
if (allocCount == 64)
{
NOP;
}
#endif
auto blockList = (ChList*)mMetadata; auto blockList = (ChList*)mMetadata;
auto block = CH_REL_TO_ABS(ref); auto block = CH_REL_TO_ABS(ref);
if (block->mKind != ChBlockKind_Used) if (block->mKind != ChBlockKind_Used)
{
#ifdef BFCE_DEBUG_HEAP
OutputDebugStrF("Invalid free\n");
Validate();
#endif
return false; return false;
}
#ifdef BFCE_DEBUG_HEAP
OutputDebugStrF("ContiguousHeap::Free %d block:%d size: %d\n", allocCount, CH_ABS_TO_REL(block), block->mSize);
#endif
int headAccSize = 0; int headAccSize = 0;
auto mergeHead = block; auto mergeHead = block;
@ -285,6 +348,9 @@ bool ContiguousHeap::Free(AllocRef ref)
mergeHead->mKind = ChBlockKind_Merged; mergeHead->mKind = ChBlockKind_Merged;
blockList->Remove(CH_ABS_TO_REL(mergeHead)); blockList->Remove(CH_ABS_TO_REL(mergeHead));
mergeHead = checkBlock; mergeHead = checkBlock;
#ifdef BFCE_DEBUG_HEAP
OutputDebugStrF(" Setting Merged block %d\n", CH_ABS_TO_REL(mergeHead));
#endif
} }
int tailAccSize = 0; int tailAccSize = 0;
@ -299,6 +365,9 @@ bool ContiguousHeap::Free(AllocRef ref)
tailAccSize += mergeTail->mSize; tailAccSize += mergeTail->mSize;
mergeTail->mKind = ChBlockKind_Merged; mergeTail->mKind = ChBlockKind_Merged;
blockList->Remove(CH_ABS_TO_REL(mergeTail)); blockList->Remove(CH_ABS_TO_REL(mergeTail));
#ifdef BFCE_DEBUG_HEAP
OutputDebugStrF(" Setting Merged block %d\n", CH_ABS_TO_REL(mergeTail));
#endif
if (nextBlock == NULL) if (nextBlock == NULL)
break; break;
mergeTail = nextBlock; mergeTail = nextBlock;
@ -313,7 +382,15 @@ bool ContiguousHeap::Free(AllocRef ref)
} }
mergeHead->mKind = ChBlockKind_Unused; mergeHead->mKind = ChBlockKind_Unused;
//OutputDebugStrF("ContiguousHeap::Free %d size: %d\n", CH_ABS_TO_REL(mergeHead), mergeHead->mSize); if (mergeHead != block)
{
// We weren't in the free list so don't mark as Merged
block->mKind = (ChBlockKind)0;
}
#ifdef BFCE_DEBUG_HEAP
Validate();
#endif
return true; return true;
} }
@ -360,9 +437,103 @@ void ContiguousHeap::DebugDump()
} }
str += "\nFree List:\n"; str += "\nFree List:\n";
for (auto val : mFreeList) for (auto idx : mFreeList)
str += StrFormat("@%d\n", val); {
auto block = CH_REL_TO_ABS(idx);
char* kind = "??";
if (block->mKind == ChBlockKind_Unused)
kind = "Unused";
else
kind = "Merged";
str += StrFormat("@%d %s\n", idx, kind);
}
str += "\n"; str += "\n";
OutputDebugStrF(str.c_str()); OutputDebugStrF(str.c_str());
} }
void ContiguousHeap::Validate()
{
if (!mFreeList.IsEmpty())
{
BF_ASSERT_REL(mMetadata != NULL);
}
HashSet<int> freeSet;
for (auto idx : mFreeList)
freeSet.Add(idx);
auto blockList = (ChList*)mMetadata;
bool deepValidate = true;
if (deepValidate)
{
if (blockList->mHead != -1)
{
int totalSize = 0;
auto block = CH_REL_TO_ABS(blockList->mHead);
auto blockEnd = (ChBlock*)((uint8*)blockList + mMemorySize);
while (block != blockEnd)
{
switch (block->mKind)
{
case (ChBlockKind)0:
BF_ASSERT_REL(!freeSet.Contains(CH_ABS_TO_REL(block)));
break;
case ChBlockKind_Unused:
BF_ASSERT_REL(freeSet.Remove(CH_ABS_TO_REL(block)));
break;
case ChBlockKind_Merged:
BF_ASSERT_REL(freeSet.Remove(CH_ABS_TO_REL(block)));
break;
case ChBlockKind_Used:
BF_ASSERT_REL(!freeSet.Contains(CH_ABS_TO_REL(block)));
break;
default:
BF_FATAL("Invalid state");
}
block = (ChBlock*)((uint8*)block + 16);
}
BF_ASSERT_REL(freeSet.IsEmpty());
}
}
else
{
if (blockList->mHead != -1)
{
int totalSize = 0;
auto block = CH_REL_TO_ABS(blockList->mHead);
while (block != NULL)
{
switch (block->mKind)
{
case ChBlockKind_Unused:
BF_ASSERT_REL(freeSet.Remove(CH_ABS_TO_REL(block)));
break;
case ChBlockKind_Used:
BF_ASSERT_REL(!freeSet.Contains(CH_ABS_TO_REL(block)));
break;
default:
BF_FATAL("Invalid state");
}
if (block->mNext == -1)
break;
block = CH_REL_TO_ABS(block->mNext);
}
}
}
for (auto idx : freeSet)
{
auto block = CH_REL_TO_ABS(idx);
BF_ASSERT_REL(block->mKind == ChBlockKind_Merged);
}
//BF_ASSERT(freeSet.IsEmpty());
}

View file

@ -26,6 +26,7 @@ public:
AllocRef Alloc(int size); AllocRef Alloc(int size);
bool Free(AllocRef ref); bool Free(AllocRef ref);
void Validate();
void DebugDump(); void DebugDump();
}; };