diff --git a/minimal_heap.h b/minimal_heap.h index 27b6cda..439053b 100644 --- a/minimal_heap.h +++ b/minimal_heap.h @@ -69,8 +69,9 @@ typedef struct _MIHP_HeapMemoryAreaHeader struct _MIHP_HeapMemoryAreaHeader* NextArea; struct _MIHP_HeapMemoryAreaHeader* PreviousArea; - struct _MIHP_Heap* OwningHeap; - struct _MIHP_HeapSegmentHeader* FirstSegment; + struct _MIHP_Heap* OwningHeap; + struct _MIHP_HeapSegmentHeader* FirstSegment; + struct _MIHP_HeapSegmentHeaderFreePayload* FirstFreeSegment; uint32_t Checksum; // Checksum must be the last member ! @@ -92,6 +93,12 @@ typedef struct _MIHP_HeapSegmentHeader } MIHP_HeapSegmentHeader; +typedef struct _MIHP_HeapSegmentHeaderFreePayload +{ + struct _MIHP_HeapSegmentHeaderFreePayload* PreviousFreeSegment; + struct _MIHP_HeapSegmentHeaderFreePayload* NextFreeSegment; +} MIHP_HeapSegmentHeaderFreePayload; + typedef struct _MIHP_HeapCorruptionInfo { uint8_t Type; @@ -134,6 +141,12 @@ bool MIHP_UninitializeHeapSegment(MIHP_HeapSegmentHeader* segment); bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegmentSize, MIHP_HeapSegmentHeader** outNewSegment); bool MIHP_MergeHeapSegments(MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegmentHeader* segmentToAbsorb); +void MIHP_AddSegmentToFreeList(MIHP_Heap* heap, MIHP_HeapSegmentHeader* segment); +void MIHP_RemoveSegmentFromFreeList(MIHP_Heap* heap, MIHP_HeapSegmentHeader* segment); + +void* MIHP_GetSegmentPayloadPtr(MIHP_Heap* heap, MIHP_HeapSegmentHeader* segment); +MIHP_HeapSegmentHeader* MIHP_GetSegmentHeaderPtr(MIHP_Heap* heap, void* payloadPtr); + size_t MIHP_GetHeapAlignedSize(const MIHP_Heap* heap, size_t size); uint32_t MIHP_HashMemoryRegion(const void* data, size_t size); diff --git a/minimal_heap_implementation.inl b/minimal_heap_implementation.inl index 78dd93a..0d420c1 100644 --- a/minimal_heap_implementation.inl +++ b/minimal_heap_implementation.inl @@ -103,12 +103,12 @@ void* MIHP_Allocate(MIHP_Heap* heap, size_t size) if (currentArea->NumOccupiedSegments == currentArea->NumSegments) continue; - MIHP_HeapSegmentHeader* nextSegment = currentArea->FirstSegment; - while (nextSegment) + MIHP_HeapSegmentHeaderFreePayload* nextFreeSegmentPayload = currentArea->FirstFreeSegment; + while (nextFreeSegmentPayload) { - MIHP_HeapSegmentHeader* currentSegment = nextSegment; + MIHP_HeapSegmentHeader* currentSegment = MIHP_GetSegmentHeaderPtr(heap, nextFreeSegmentPayload); MIHP_ValidateHeapSegmentHeader(heap, currentSegment); - nextSegment = currentSegment->NextSegment; + nextFreeSegmentPayload = nextFreeSegmentPayload->NextFreeSegment; if (currentSegment->OccupiedSize != 0) continue; @@ -123,6 +123,7 @@ void* MIHP_Allocate(MIHP_Heap* heap, size_t size) else continue; + MIHP_RemoveSegmentFromFreeList(heap, targetSegment); targetSegment->OccupiedSize = size; targetSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(targetSegment); @@ -134,7 +135,7 @@ void* MIHP_Allocate(MIHP_Heap* heap, size_t size) MIHP_UNLOCK_HEAP(&heap->HeapLock); - void* data = (char*)targetSegment + segmentHeaderSize; + void* data = MIHP_GetSegmentPayloadPtr(heap, targetSegment); MIHP_MEMSET(data, size, heap->Config.AllocationInitialValue); return data; @@ -181,10 +182,10 @@ void* MIHP_Realloc(MIHP_Heap* heap, void* ptr, size_t newSize) MIHP_LOCK_HEAP(&heap->HeapLock); - size_t segmentHeaderSize = MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapSegmentHeader)); - MIHP_HeapSegmentHeader* segment = (MIHP_HeapSegmentHeader*)((char*)ptr - segmentHeaderSize); + MIHP_HeapSegmentHeader* segment = MIHP_GetSegmentHeaderPtr(heap, ptr); MIHP_ValidateHeapSegmentHeader(heap, segment); + size_t segmentHeaderSize = MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapSegmentHeader)); if (newSize > segment->OccupiedSize) { size_t maxPayloadSize = segment->SegmentSize - segmentHeaderSize; @@ -253,8 +254,7 @@ bool MIHP_Free(MIHP_Heap* heap, void* ptr) MIHP_LOCK_HEAP(&heap->HeapLock); - size_t segmentHeaderSize = MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapSegmentHeader)); - MIHP_HeapSegmentHeader* segment = (MIHP_HeapSegmentHeader*)((char*)ptr - segmentHeaderSize); + MIHP_HeapSegmentHeader* segment = MIHP_GetSegmentHeaderPtr(heap, ptr); MIHP_ValidateHeapSegmentHeader(heap, segment); MIHP_HeapMemoryAreaHeader* area = segment->OwningMemoryArea; @@ -278,6 +278,8 @@ bool MIHP_Free(MIHP_Heap* heap, void* ptr) heap->Stats.NumTotalOccupiedSegments--; + MIHP_AddSegmentToFreeList(heap, segment); + if (area->NumOccupiedSegments == 0 && heap->Stats.NumMemoryAreas > 1) { MIHP_HeapMemoryAreaHeader* prevArea = area->PreviousArea; @@ -454,6 +456,8 @@ MIHP_HeapSegmentHeader* MIHP_InitializeHeapSegment(MIHP_HeapMemoryAreaHeader* ar area->OwningHeap->Stats.NumTotalSegments++; + MIHP_AddSegmentToFreeList(area->OwningHeap, segment); + return segment; } @@ -464,6 +468,8 @@ bool MIHP_UninitializeHeapSegment(MIHP_HeapSegmentHeader* segment) if (segment->OccupiedSize > 0) return false; + MIHP_RemoveSegmentFromFreeList(segment->OwningMemoryArea->OwningHeap, segment); + segment->OwningMemoryArea->NumSegments--; segment->OwningMemoryArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(segment->OwningMemoryArea); segment->OwningMemoryArea->OwningHeap->Stats.NumTotalSegments--; @@ -536,6 +542,61 @@ bool MIHP_MergeHeapSegments(MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegm return true; } +void MIHP_AddSegmentToFreeList(MIHP_Heap* heap, MIHP_HeapSegmentHeader* segment) +{ + MIHP_ASSERT(segment->OccupiedSize == 0); + MIHP_HeapMemoryAreaHeader* area = segment->OwningMemoryArea; + MIHP_HeapSegmentHeaderFreePayload* list = (MIHP_HeapSegmentHeaderFreePayload*)MIHP_GetSegmentPayloadPtr(heap, segment); + + list->PreviousFreeSegment = NULL; + list->NextFreeSegment = area->FirstFreeSegment; + + if (area->FirstFreeSegment) + area->FirstFreeSegment->PreviousFreeSegment = list; + + area->FirstFreeSegment = list; + area->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(area); +} + +void MIHP_RemoveSegmentFromFreeList(MIHP_Heap* heap, MIHP_HeapSegmentHeader* segment) +{ + MIHP_ASSERT(segment->OccupiedSize == 0); + + MIHP_HeapMemoryAreaHeader* area = segment->OwningMemoryArea; + MIHP_HeapSegmentHeaderFreePayload* list = (MIHP_HeapSegmentHeaderFreePayload*)MIHP_GetSegmentPayloadPtr(heap, segment); + + if (list->PreviousFreeSegment) + list->PreviousFreeSegment->NextFreeSegment = list->NextFreeSegment; + + if (list->NextFreeSegment) + list->NextFreeSegment->PreviousFreeSegment = list->PreviousFreeSegment; + + if (area->FirstFreeSegment == list) + { + area->FirstFreeSegment = list->NextFreeSegment; + area->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(area); + } + + list->NextFreeSegment = NULL; + list->PreviousFreeSegment = NULL; +} + +void* MIHP_GetSegmentPayloadPtr(MIHP_Heap* heap, MIHP_HeapSegmentHeader* segment) +{ + MIHP_ASSERT(heap); + MIHP_ASSERT(segment); + + return (char*)segment + MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapSegmentHeader)); +} + +MIHP_HeapSegmentHeader* MIHP_GetSegmentHeaderPtr(MIHP_Heap* heap, void* payloadPtr) +{ + MIHP_ASSERT(heap); + MIHP_ASSERT(payloadPtr); + + return (MIHP_HeapSegmentHeader*)((char*)payloadPtr - MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapSegmentHeader))); +} + size_t MIHP_GetHeapAlignedSize(const MIHP_Heap* heap, size_t size) { return (size + (heap->Config.AllocationAlignment - 1)) & ~(heap->Config.AllocationAlignment - 1); @@ -647,5 +708,5 @@ void MIHP_ValidateHeapSegmentHeader(const MIHP_Heap* heap, const MIHP_HeapSegmen size_t MIHP_GetMinimalPayloadSize(const MIHP_Heap* heap) { - return heap->Config.AllocationAlignment; + return MIHP_MAX(heap->Config.AllocationAlignment, sizeof(MIHP_HeapSegmentHeaderFreePayload)); } diff --git a/minimal_heap_test.c b/minimal_heap_test.c index 1f6f4af..594144a 100644 --- a/minimal_heap_test.c +++ b/minimal_heap_test.c @@ -26,14 +26,14 @@ void MIHP_PlatformOnHeapCorruptionDetected(const MIHP_Heap* heap, MIHP_HeapCorru __debugbreak(); } -#define NUM_ALLOCATIONS (4096 * 4) +#define NUM_ALLOCATIONS (4096 * 128) -void* myptrs[NUM_ALLOCATIONS] = { 0 }; +char* myptrs[NUM_ALLOCATIONS] = { 0 }; int main() { MIHP_HeapConfig config = {0}; - config.AllocationInitialValue = 0xbe; + config.AllocationInitialValue = 'f'; //0xbe; config.AllocationAlignment = 16; config.MinimalMemoryAreaSize = 4096 * 32; config.MaximalMemoryAreaSize = 4096ull * 4096ull * 4096ull; @@ -48,6 +48,7 @@ int main() myptrs[i] = malloc(size); #else myptrs[i] = MIHP_Allocate(&myHeap, size); + myptrs[i][size - 1] = '\0'; MIHP_ValidateHeap(&myHeap); #endif } @@ -74,14 +75,16 @@ int main() for (int i = 0; i < NUM_ALLOCATIONS; i++) { volatile int n = i; - if (myptrs[i]) + if (!myptrs[i]) { size_t size = 300 + rand() % 500; #if USE_MALLOC myptrs[i] = realloc(myptrs[i], size); #else - myptrs[i] = MIHP_Realloc(&myHeap, myptrs[i], size); + //myptrs[i] = MIHP_Realloc(&myHeap, myptrs[i], size); + myptrs[i] = MIHP_Allocate(&myHeap, size); + myptrs[i][size - 1] = '\0'; MIHP_ValidateHeap(&myHeap);