|
|
|
|
@@ -1,4 +1,3 @@
|
|
|
|
|
#include "minimal_heap.h"
|
|
|
|
|
#define MIHP_MIN(A, B) ((A) < (B) ? (A) : (B))
|
|
|
|
|
#define MIHP_MAX(A, B) ((A) > (B) ? (A) : (B))
|
|
|
|
|
|
|
|
|
|
@@ -22,9 +21,10 @@ MIHP_HeapConfig MIHP_MakeDefaultConfigPreset()
|
|
|
|
|
cfg.MinHeapTraversalPercentToExpand = 80;
|
|
|
|
|
|
|
|
|
|
cfg.AllocationAlignment = 16;
|
|
|
|
|
cfg.AllocationInitialValue = 0xbe;
|
|
|
|
|
cfg.AllocateFillValue = 0xbe;
|
|
|
|
|
cfg.FreeFillValue = 0xee;
|
|
|
|
|
|
|
|
|
|
cfg.HeapValidationMode = MIHP_HVM_MagicNumber;
|
|
|
|
|
cfg.HeapValidationMode = MIHP_HVM_None;
|
|
|
|
|
|
|
|
|
|
return cfg;
|
|
|
|
|
}
|
|
|
|
|
@@ -43,6 +43,12 @@ MIHP_HeapError MIHP_InitializeHeap(MIHP_Heap* heap, MIHP_HeapConfig config)
|
|
|
|
|
if (config.PlatformFreeMemoryFn == NULL)
|
|
|
|
|
return MIHP_HE_BadConfig;
|
|
|
|
|
|
|
|
|
|
if (config.OnHeapCorruptionDetectedFn == NULL && config.HeapValidationMode != MIHP_HVM_None)
|
|
|
|
|
return MIHP_HE_BadConfig;
|
|
|
|
|
|
|
|
|
|
if (config.MinMemoryAreaSize < MIHP_GetMinimalPayloadSize(heap) * 2)
|
|
|
|
|
return MIHP_HE_BadConfig;
|
|
|
|
|
|
|
|
|
|
if (config.MaxHeapSize < config.MinMemoryAreaSize)
|
|
|
|
|
return MIHP_HE_BadConfig;
|
|
|
|
|
|
|
|
|
|
@@ -73,7 +79,7 @@ MIHP_HeapError MIHP_InitializeHeap(MIHP_Heap* heap, MIHP_HeapConfig config)
|
|
|
|
|
return MIHP_HE_BadConfig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MIHP_MEMSET(heap, sizeof(MIHP_Heap), 0);
|
|
|
|
|
MIHP_MEMSET(heap, 0, sizeof(MIHP_Heap));
|
|
|
|
|
|
|
|
|
|
heap->Config = config;
|
|
|
|
|
heap->FirstArea = MIHP_CreateHeapMemoryArea(heap, config.MinMemoryAreaSize);
|
|
|
|
|
@@ -112,7 +118,7 @@ MIHP_HeapError MIHP_UninitializeHeap(MIHP_Heap* heap, bool force)
|
|
|
|
|
MIHP_DestroyHeapMemoryArea(heap, currentArea);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MIHP_MEMSET(heap, sizeof(MIHP_Heap), 0);
|
|
|
|
|
MIHP_MEMSET(heap, 0, sizeof(MIHP_Heap));
|
|
|
|
|
return MIHP_HE_Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -190,7 +196,7 @@ MIHP_HeapResult MIHP_Allocate(MIHP_Heap* heap, size_t size)
|
|
|
|
|
MIHP_UnlockHeap(heap);
|
|
|
|
|
|
|
|
|
|
void* data = MIHP_GetHeapSegmentPayloadPtr(heap, targetSegment);
|
|
|
|
|
MIHP_MEMSET(data, size, heap->Config.AllocationInitialValue);
|
|
|
|
|
MIHP_MEMSET(data, heap->Config.AllocateFillValue, size);
|
|
|
|
|
|
|
|
|
|
return MIHP_MAKE_RESULT(data, MIHP_HE_Success);
|
|
|
|
|
} while (nextSegment != currentArea->LastSuccessfulAllocationSegment);
|
|
|
|
|
@@ -255,12 +261,12 @@ MIHP_HeapResult MIHP_Reallocate(MIHP_Heap* heap, void* ptr, size_t newSize)
|
|
|
|
|
size_t maxPayloadSize = segment->SegmentSize - segmentHeaderSize;
|
|
|
|
|
if (newSize <= maxPayloadSize)
|
|
|
|
|
{
|
|
|
|
|
MIHP_MEMSET((char*)ptr + segment->OccupiedSize, newSize - segment->OccupiedSize, heap->Config.AllocationInitialValue);
|
|
|
|
|
MIHP_MEMSET((char*)ptr + segment->OccupiedSize, heap->Config.AllocateFillValue, newSize - segment->OccupiedSize);
|
|
|
|
|
segment->OccupiedSize = newSize;
|
|
|
|
|
segment->Checksum = MIHP_GenerateHeapSegmentChecksum(heap, segment);
|
|
|
|
|
|
|
|
|
|
MIHP_UnlockHeap(heap);
|
|
|
|
|
return MIHP_MAKE_RESULT(NULL, MIHP_HE_Success);
|
|
|
|
|
return MIHP_MAKE_RESULT(ptr, MIHP_HE_Success);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (segment->NextSegment)
|
|
|
|
|
@@ -289,6 +295,8 @@ MIHP_HeapResult MIHP_Reallocate(MIHP_Heap* heap, void* ptr, size_t newSize)
|
|
|
|
|
}
|
|
|
|
|
else if (newSize < segment->OccupiedSize)
|
|
|
|
|
{
|
|
|
|
|
MIHP_MEMSET((char*)ptr + newSize, heap->Config.FreeFillValue, segment->OccupiedSize - newSize);
|
|
|
|
|
|
|
|
|
|
segment->OccupiedSize = newSize;
|
|
|
|
|
segment->Checksum = MIHP_GenerateHeapSegmentChecksum(heap, segment);
|
|
|
|
|
|
|
|
|
|
@@ -325,17 +333,18 @@ MIHP_HeapError MIHP_Free(MIHP_Heap* heap, void* ptr)
|
|
|
|
|
|
|
|
|
|
if (segment->OccupiedSize == 0)
|
|
|
|
|
{
|
|
|
|
|
MIHP_HeapCorruptionInfo corruptionInfo = { 0 };
|
|
|
|
|
MIHP_HeapCorruptionInfo corruptionInfo;
|
|
|
|
|
corruptionInfo.Error = MIHP_HCE_DoubleFree;
|
|
|
|
|
corruptionInfo.Ptr = ptr;
|
|
|
|
|
corruptionInfo.ExpectedValue = 0;
|
|
|
|
|
corruptionInfo.ActualValue = 0;
|
|
|
|
|
|
|
|
|
|
if (heap->Config.OnHeapCorruptionDetectedFn != NULL)
|
|
|
|
|
heap->Config.OnHeapCorruptionDetectedFn(heap, corruptionInfo);
|
|
|
|
|
|
|
|
|
|
MIHP_UnlockHeap(heap);
|
|
|
|
|
return MIHP_HE_InvalidOperation;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MIHP_MEMSET(ptr, heap->Config.FreeFillValue, segment->OccupiedSize);
|
|
|
|
|
|
|
|
|
|
segment->OccupiedSize = 0;
|
|
|
|
|
segment->Checksum = MIHP_GenerateHeapSegmentChecksum(heap, segment);
|
|
|
|
|
|
|
|
|
|
@@ -396,9 +405,14 @@ MIHP_HeapError MIHP_SetPointerCustomMetadata(MIHP_Heap* heap, void* ptr, MIHP_Al
|
|
|
|
|
if (!MIHP_IsAddressInHeap(heap, ptr))
|
|
|
|
|
return MIHP_HE_InvalidHeap;
|
|
|
|
|
|
|
|
|
|
MIHP_LockHeap(heap);
|
|
|
|
|
|
|
|
|
|
MIHP_HeapSegmentHeader* segment = MIHP_GetHeapSegmentHeaderPtr(heap, ptr);
|
|
|
|
|
MIHP_ValidateHeapSegmentHeader(heap, segment);
|
|
|
|
|
segment->CustomMetadata = metadata;
|
|
|
|
|
segment->Checksum = MIHP_GenerateHeapSegmentChecksum(heap, segment);
|
|
|
|
|
|
|
|
|
|
MIHP_UnlockHeap(heap);
|
|
|
|
|
return MIHP_HE_Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -410,14 +424,22 @@ MIHP_HeapError MIHP_GetPointerCustomMetadata(MIHP_Heap* heap, void* ptr, MIHP_Al
|
|
|
|
|
if (!MIHP_IsAddressInHeap(heap, ptr))
|
|
|
|
|
return MIHP_HE_InvalidHeap;
|
|
|
|
|
|
|
|
|
|
MIHP_LockHeap(heap);
|
|
|
|
|
|
|
|
|
|
MIHP_HeapSegmentHeader* segment = MIHP_GetHeapSegmentHeaderPtr(heap, ptr);
|
|
|
|
|
MIHP_ValidateHeapSegmentHeader(heap, segment);
|
|
|
|
|
*outMetadata = segment->CustomMetadata;
|
|
|
|
|
|
|
|
|
|
MIHP_UnlockHeap(heap);
|
|
|
|
|
|
|
|
|
|
return MIHP_HE_Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MIHP_HeapError MIHP_MergeHeaps(MIHP_Heap* sourceHeap, MIHP_Heap* heapToAbsorb)
|
|
|
|
|
{
|
|
|
|
|
if (sourceHeap == heapToAbsorb)
|
|
|
|
|
return MIHP_HE_InvalidParameter;
|
|
|
|
|
|
|
|
|
|
if (!MIHP_IsHeapInitialized(sourceHeap))
|
|
|
|
|
return MIHP_HE_InvalidHeap;
|
|
|
|
|
|
|
|
|
|
@@ -463,7 +485,7 @@ MIHP_HeapError MIHP_MergeHeaps(MIHP_Heap* sourceHeap, MIHP_Heap* heapToAbsorb)
|
|
|
|
|
sourceHeap->Stats.TotalSize += heapToAbsorb->Stats.TotalSize;
|
|
|
|
|
|
|
|
|
|
MIHP_UnlockHeap(heapToAbsorb);
|
|
|
|
|
MIHP_MEMSET(heapToAbsorb, sizeof(MIHP_Heap), 0);
|
|
|
|
|
MIHP_MEMSET(heapToAbsorb, 0, sizeof(MIHP_Heap));
|
|
|
|
|
|
|
|
|
|
sourceEndArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(sourceHeap, sourceEndArea);
|
|
|
|
|
sourceEndArea->NextArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(sourceHeap, sourceEndArea->NextArea);
|
|
|
|
|
@@ -490,7 +512,7 @@ bool MIHP_IsAddressInHeap(MIHP_Heap* heap, void* ptr)
|
|
|
|
|
uintptr_t ptrMin = (uintptr_t)currentArea;
|
|
|
|
|
uintptr_t ptrMax = (uintptr_t)currentArea + currentArea->AreaSize;
|
|
|
|
|
|
|
|
|
|
if (searchingPtr >= ptrMin && searchingPtr <= ptrMax)
|
|
|
|
|
if (searchingPtr >= ptrMin && searchingPtr < ptrMax)
|
|
|
|
|
{
|
|
|
|
|
MIHP_UnlockHeap(heap);
|
|
|
|
|
return true;
|
|
|
|
|
@@ -558,6 +580,8 @@ MIHP_HeapError MIHP_WalkHeap(MIHP_Heap* heap, MIHP_WalkHeapCallbackFn* callback)
|
|
|
|
|
if (callback == NULL)
|
|
|
|
|
return MIHP_HE_InvalidParameter;
|
|
|
|
|
|
|
|
|
|
MIHP_LockHeap(heap);
|
|
|
|
|
|
|
|
|
|
MIHP_HeapMemoryAreaHeader* nextArea = heap->FirstArea;
|
|
|
|
|
while (nextArea != NULL)
|
|
|
|
|
{
|
|
|
|
|
@@ -576,6 +600,8 @@ MIHP_HeapError MIHP_WalkHeap(MIHP_Heap* heap, MIHP_WalkHeapCallbackFn* callback)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MIHP_UnlockHeap(heap);
|
|
|
|
|
|
|
|
|
|
return MIHP_HE_Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -607,8 +633,11 @@ MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_Heap* heap, size_t req
|
|
|
|
|
if (area == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
MIHP_ASSERT((uintptr_t)area % heap->Config.AllocationAlignment == 0);
|
|
|
|
|
MIHP_ASSERT(actualSize % heap->Config.AllocationAlignment == 0);
|
|
|
|
|
MIHP_ASSERT(actualSize >= effectiveSize);
|
|
|
|
|
MIHP_MEMSET(area, sizeof(MIHP_HeapMemoryAreaHeader), 0);
|
|
|
|
|
|
|
|
|
|
MIHP_MEMSET(area, 0, sizeof(MIHP_HeapMemoryAreaHeader));
|
|
|
|
|
|
|
|
|
|
area->InstigatingHeap = (MIHP_HeapOpaque)heap;
|
|
|
|
|
area->AreaSize = actualSize;
|
|
|
|
|
@@ -652,7 +681,7 @@ MIHP_HeapSegmentHeader* MIHP_InitializeHeapSegment(MIHP_Heap* heap, MIHP_HeapMem
|
|
|
|
|
|
|
|
|
|
MIHP_HeapSegmentHeader* segment = (MIHP_HeapSegmentHeader*)segmentStart;
|
|
|
|
|
|
|
|
|
|
MIHP_MEMSET(segment, sizeof(MIHP_HeapSegmentHeader), 0);
|
|
|
|
|
MIHP_MEMSET(segment, 0, sizeof(MIHP_HeapSegmentHeader));
|
|
|
|
|
|
|
|
|
|
segment->SegmentSize = segmentSize;
|
|
|
|
|
segment->OwningMemoryArea = area;
|
|
|
|
|
@@ -677,7 +706,7 @@ bool MIHP_UninitializeHeapSegment(MIHP_Heap* heap, MIHP_HeapSegmentHeader* segme
|
|
|
|
|
segment->OwningMemoryArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(heap, segment->OwningMemoryArea);
|
|
|
|
|
heap->Stats.NumTotalSegments--;
|
|
|
|
|
|
|
|
|
|
MIHP_MEMSET(segment, sizeof(MIHP_HeapSegmentHeader), 0);
|
|
|
|
|
MIHP_MEMSET(segment, 0, sizeof(MIHP_HeapSegmentHeader));
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
@@ -823,9 +852,6 @@ uint32_t MIHP_GenerateHeapSegmentChecksum(const MIHP_Heap* heap, const MIHP_Heap
|
|
|
|
|
|
|
|
|
|
void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_Heap* heap, const MIHP_HeapMemoryAreaHeader* area)
|
|
|
|
|
{
|
|
|
|
|
if (heap->Config.OnHeapCorruptionDetectedFn == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
uint32_t newChecksum;
|
|
|
|
|
|
|
|
|
|
if (heap->Config.HeapValidationMode == MIHP_HVM_None)
|
|
|
|
|
@@ -852,9 +878,6 @@ void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_Heap* heap, const MIHP_HeapMem
|
|
|
|
|
|
|
|
|
|
void MIHP_ValidateHeapSegmentHeader(const MIHP_Heap* heap, const MIHP_HeapSegmentHeader* segment)
|
|
|
|
|
{
|
|
|
|
|
if (heap->Config.OnHeapCorruptionDetectedFn == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
uint32_t newChecksum;
|
|
|
|
|
|
|
|
|
|
if (heap->Config.HeapValidationMode == MIHP_HVM_None)
|
|
|
|
|
|