diff --git a/minimal_heap.h b/minimal_heap.h index a89c758..a3510e0 100644 --- a/minimal_heap.h +++ b/minimal_heap.h @@ -25,22 +25,21 @@ #endif #ifndef MIHP_HEAP_LOCK_TYPE - #define MIHP_HEAP_LOCK_TYPE bool // Does NOT have to be reentred safe + #define MIHP_HEAP_LOCK_TYPE volatile bool // Does NOT have to be reentred safe #define MIHP_LOCK_HEAP(LockVarPtr) { while (*(LockVarPtr)) {}; *(LockVarPtr) = true; } #define MIHP_UNLOCK_HEAP(LockVarPtr) { *(LockVarPtr) = false; } #endif /* */ /* Hooks to be implemented by the library user */ -void* MIHP_PlatformRequestMemory(size_t size); // Alignment must at least be alignment of size_t -bool MIHP_PlatformFreeMemory(void* ptr, size_t size); +void* MIHP_PlatformRequestMemory(size_t minRequestedSize, size_t* outActualSize); // Alignment must at least be alignment of size_t, outActualSize must at least be minRequestedSize +bool MIHP_PlatformFreeMemory(void* ptr, size_t actualSize); void MIHP_PlatformOnHeapCorruptionDetected(struct _MIHP_HeapCorruptionInfo info); /* */ #define MIHP_HEAP_CORRUPTION_TYPE_MEMORY_AREA_CHECKSUM_MISMATCH 0 #define MIHP_HEAP_CORRUPTION_TYPE_SEGMENT_CHECKSUM_MISMATCH 1 -#define MIHP_HEAP_CORRUPTION_TYPE_FRONT_CANARY_MISMATCH 2 -#define MIHP_HEAP_CORRUPTION_TYPE_REAR_CANARY_MISMATCH 3 +#define MIHP_HEAP_CORRUPTION_TYPE_DOUBLE_FREE 2 typedef struct _MIHP_HeapConfig { @@ -109,6 +108,8 @@ typedef struct _MIHP_Heap MIHP_HeapMemoryAreaHeader* FirstArea; MIHP_HeapMemoryAreaHeader* LastSuccessfulAllocationArea; + size_t HeapStructureAllocationSize; + MIHP_HEAP_LOCK_TYPE HeapLock; } MIHP_Heap; @@ -131,7 +132,7 @@ bool MIHP_DestroyHeapMemoryArea(MIHP_Heap* heap, MIHP_HeapMemoryAreaHeader* area MIHP_HeapSegmentHeader* MIHP_InitializeHeapSegment(MIHP_HeapMemoryAreaHeader* area, void* segmentStart, size_t size); bool MIHP_UninitializeHeapSegment(MIHP_HeapSegmentHeader* segment); -bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegmentSize, MIHP_HeapSegmentHeader** outNewSegment); +bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegmentSize, MIHP_HeapSegmentHeader** optOutNewSegment); bool MIHP_MergeHeapSegments(MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegmentHeader* segmentToAbsorb); size_t MIHP_GetHeapAlignedSize(const MIHP_Heap* heap, size_t size); diff --git a/minimal_heap_implementation.inl b/minimal_heap_implementation.inl index 592935e..df69f37 100644 --- a/minimal_heap_implementation.inl +++ b/minimal_heap_implementation.inl @@ -19,19 +19,22 @@ MIHP_Heap* MIHP_CreateHeap(MIHP_HeapConfig config) if (config.MaximalMemoryAreaSize % config.AllocationAlignment != 0) return NULL; - MIHP_Heap* heap = (MIHP_Heap*)MIHP_PlatformRequestMemory(sizeof(MIHP_Heap)); + size_t actualHeapStructAllocSize = 0; + MIHP_Heap* heap = (MIHP_Heap*)MIHP_PlatformRequestMemory(sizeof(MIHP_Heap), &actualHeapStructAllocSize); if (heap == NULL) return NULL; + MIHP_ASSERT(actualHeapStructAllocSize >= sizeof(MIHP_Heap)); MIHP_MEMSET(heap, sizeof(MIHP_Heap), 0); heap->Config = config; - - heap->FirstArea = MIHP_CreateHeapMemoryArea(heap, config.MinimalMemoryAreaSize); + heap->HeapStructureAllocationSize = actualHeapStructAllocSize; + heap->FirstArea = MIHP_CreateHeapMemoryArea(heap, actualHeapStructAllocSize); heap->LastSuccessfulAllocationArea = heap->FirstArea; + if (heap->FirstArea == NULL) { - MIHP_PlatformFreeMemory(heap, sizeof(MIHP_Heap)); + MIHP_PlatformFreeMemory(heap, heap->HeapStructureAllocationSize); return NULL; } @@ -58,7 +61,7 @@ bool MIHP_DestroyHeap(MIHP_Heap* heap, bool force) MIHP_DestroyHeapMemoryArea(heap, currentArea); } - MIHP_PlatformFreeMemory(heap, sizeof(MIHP_Heap)); + MIHP_PlatformFreeMemory(heap, heap->HeapStructureAllocationSize); return true; } @@ -254,6 +257,17 @@ bool MIHP_Free(MIHP_Heap* heap, void* ptr) MIHP_HeapMemoryAreaHeader* area = segment->OwningMemoryArea; MIHP_ValidateHeapMemoryAreaHeader(heap, area); + if (segment->OccupiedSize == 0) + { + MIHP_HeapCorruptionInfo corruptionInfo = {0}; + corruptionInfo.Heap = heap; + corruptionInfo.Type = MIHP_HEAP_CORRUPTION_TYPE_DOUBLE_FREE; + corruptionInfo.Ptr = ptr; + + MIHP_PlatformOnHeapCorruptionDetected(corruptionInfo); + return false; + } + segment->OccupiedSize = 0; segment->Checksum = MIHP_GenerateHeapSegmentChecksum(segment); @@ -378,13 +392,15 @@ MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_Heap* heap, size_t req effectiveSize = MIHP_MAX(effectiveSize, heap->Config.MinimalMemoryAreaSize); effectiveSize = MIHP_MIN(effectiveSize, heap->Config.MaximalMemoryAreaSize); - MIHP_HeapMemoryAreaHeader* area = (MIHP_HeapMemoryAreaHeader*)MIHP_PlatformRequestMemory(effectiveSize); + size_t actualSize = 0; + MIHP_HeapMemoryAreaHeader* area = (MIHP_HeapMemoryAreaHeader*)MIHP_PlatformRequestMemory(effectiveSize, &actualSize); if (area == NULL) return NULL; + MIHP_ASSERT(actualSize >= effectiveSize); MIHP_MEMSET(area, sizeof(MIHP_HeapMemoryAreaHeader), 0); - area->AreaSize = effectiveSize; + area->AreaSize = actualSize; area->OwningHeap = heap; area->Checksum = ~0; @@ -393,7 +409,7 @@ MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_Heap* heap, size_t req area->FirstSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(area->FirstSegment); heap->Stats.NumMemoryAreas++; - heap->Stats.TotalSize += effectiveSize; + heap->Stats.TotalSize += area->AreaSize; return area; } @@ -455,7 +471,7 @@ bool MIHP_UninitializeHeapSegment(MIHP_HeapSegmentHeader* segment) return true; } -bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegmentMinSize, MIHP_HeapSegmentHeader** outNewSegment) +bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegmentMinSize, MIHP_HeapSegmentHeader** optOutNewSegment) { MIHP_ASSERT(sourceSegment); @@ -485,8 +501,8 @@ bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegm sourceSegment->NextSegment = newSegment; - if (outNewSegment) - *outNewSegment = newSegment; + if (optOutNewSegment) + *optOutNewSegment = newSegment; newSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(newSegment); sourceSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(sourceSegment); diff --git a/minimal_heap_test.c b/minimal_heap_test.c index 4c194d0..d8405cb 100644 --- a/minimal_heap_test.c +++ b/minimal_heap_test.c @@ -7,14 +7,15 @@ #define USE_MALLOC 0 -//#define MIHP_ValidateHeap() +#define MIHP_ValidateHeap(x) -void* MIHP_PlatformRequestMemory(size_t size) +void* MIHP_PlatformRequestMemory(size_t minRequestedSize, size_t* outActualSize) { - return malloc(size); + *outActualSize = minRequestedSize; + return malloc(minRequestedSize); } -bool MIHP_PlatformFreeMemory(void* ptr, size_t size) +bool MIHP_PlatformFreeMemory(void* ptr, size_t actualSize) { free(ptr); return true;