diff --git a/minimal_heap.h b/minimal_heap.h index 4689978..1ee1270 100644 --- a/minimal_heap.h +++ b/minimal_heap.h @@ -1,4 +1,4 @@ -/* Version 1.5 */ +/* Version 1.6 */ #ifndef __MINIMAL_HEAP_H__ #define __MINIMAL_HEAP_H__ @@ -44,7 +44,7 @@ typedef bool (MIHP_PlatformFreeMemoryFn)(const struct _MIHP_Heap* heap, void* pt #define MIHP_HEAP_CORRUPTION_TYPE_SEGMENT_CHECKSUM_MISMATCH 1 #define MIHP_HEAP_CORRUPTION_TYPE_DOUBLE_FREE 2 -typedef void (MIHP_OnHeapCorruptionDetectedFn)(const struct _MIHP_Heap* heap, struct _MIHP_HeapCorruptionInfo); +typedef void (MIHP_OnHeapCorruptionDetectedFn)(const struct _MIHP_Heap* heap, struct _MIHP_HeapCorruptionInfo corruptionInfo); typedef void(MIHIP_LockHeapFn)(const struct _MIHP_Heap* heap, void* heapLock); typedef void(MIHIP_UnlockHeapFn)(const struct _MIHP_Heap* heap, void* heapLock); @@ -84,8 +84,9 @@ typedef struct _MIHP_HeapMemoryAreaHeader struct _MIHP_HeapMemoryAreaHeader* NextArea; struct _MIHP_HeapMemoryAreaHeader* PreviousArea; - struct _MIHP_Heap* OwningHeap; - struct _MIHP_HeapSegmentHeader* FirstSegment; + struct _MIHP_HeapSegmentHeader* FirstSegment; + + const struct _MIHP_Heap* InstigatingHeap; // Heap that created this area. May not always be the owning heap (in case of a merge) or safe to deference! uint32_t Checksum; // Checksum must be the last member ! } MIHP_HeapMemoryAreaHeader; @@ -131,6 +132,8 @@ void* MIHP_Allocate(MIHP_Heap* heap, size_t size); void* MIHP_Reallocate(MIHP_Heap* heap, void* ptr, size_t newSize); bool MIHP_Free(MIHP_Heap* heap, void* ptr); +bool MIHP_MergeHeaps(MIHP_Heap* sourceHeap, MIHP_Heap* heapToAbsorb); + bool MIHP_IsPointerInHeap(MIHP_Heap* heap, void* ptr); size_t MIHP_GetPtrAllocationSize(MIHP_Heap* heap, void* ptr); void MIHP_ValidateHeap(MIHP_Heap* heap); @@ -143,11 +146,11 @@ void MIHP_UnlockHeap(MIHP_Heap* heap); MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_Heap* heap, size_t requestedSize); 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); +MIHP_HeapSegmentHeader* MIHP_InitializeHeapSegment(MIHP_Heap* heap, MIHP_HeapMemoryAreaHeader* area, void* segmentStart, size_t size); +bool MIHP_UninitializeHeapSegment(MIHP_Heap* heap, MIHP_HeapSegmentHeader* segment); -bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegmentSize, MIHP_HeapSegmentHeader** outNewSegment); -bool MIHP_MergeHeapSegments(MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegmentHeader* segmentToAbsorb); +bool MIHP_SplitHeapSegment(MIHP_Heap* heap, MIHP_HeapSegmentHeader* sourceSegment, size_t newSegmentSize, MIHP_HeapSegmentHeader** outNewSegment); +bool MIHP_MergeHeapSegments(MIHP_Heap* heap, MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegmentHeader* segmentToAbsorb); void* MIHP_GetSegmentPayloadPtr(MIHP_Heap* heap, MIHP_HeapSegmentHeader* segment); MIHP_HeapSegmentHeader* MIHP_GetSegmentHeaderPtr(MIHP_Heap* heap, void* payloadPtr); diff --git a/minimal_heap_implementation.inl b/minimal_heap_implementation.inl index fc3b80c..9c3e6f2 100644 --- a/minimal_heap_implementation.inl +++ b/minimal_heap_implementation.inl @@ -131,7 +131,7 @@ void* MIHP_Allocate(MIHP_Heap* heap, size_t size) MIHP_HeapSegmentHeader* targetSegment = NULL; if (currentSegment->SegmentSize >= 2 * segmentHeaderSize + size + MIHP_GetMinimalPayloadSize(heap)) - MIHP_SplitHeapSegment(currentSegment, segmentHeaderSize + size, &targetSegment); + MIHP_SplitHeapSegment(heap, currentSegment, segmentHeaderSize + size, &targetSegment); else if (currentSegment->SegmentSize >= segmentHeaderSize + size) targetSegment = currentSegment; else @@ -217,7 +217,7 @@ void* MIHP_Reallocate(MIHP_Heap* heap, void* ptr, size_t newSize) return ptr; } - if (segment->NextSegment && MIHP_MergeHeapSegments(segment, segment->NextSegment)) + if (segment->NextSegment && MIHP_MergeHeapSegments(heap, segment, segment->NextSegment)) { MIHP_UnlockHeap(heap); return MIHP_Reallocate(heap, ptr, newSize); @@ -246,9 +246,9 @@ void* MIHP_Reallocate(MIHP_Heap* heap, void* ptr, size_t newSize) size_t newSplitSegmentSize = segment->SegmentSize - segmentHeaderSize - alignedNewSize; MIHP_HeapSegmentHeader* newSpittedSegment = NULL; - MIHP_SplitHeapSegment(segment, newSplitSegmentSize, &newSpittedSegment); + MIHP_SplitHeapSegment(heap, segment, newSplitSegmentSize, &newSpittedSegment); if (newSpittedSegment && newSpittedSegment->NextSegment) - MIHP_MergeHeapSegments(newSpittedSegment, newSpittedSegment->NextSegment); + MIHP_MergeHeapSegments(heap, newSpittedSegment, newSpittedSegment->NextSegment); } MIHP_UnlockHeap(heap); @@ -333,20 +333,78 @@ bool MIHP_Free(MIHP_Heap* heap, void* ptr) { MIHP_ValidateHeapSegmentHeader(heap, segment->NextSegment); if (segment->NextSegment->OccupiedSize == 0) - MIHP_MergeHeapSegments(segment, segment->NextSegment); + MIHP_MergeHeapSegments(heap, segment, segment->NextSegment); } if (segment->PreviousSegment) { MIHP_ValidateHeapSegmentHeader(heap, segment->PreviousSegment); if (segment->PreviousSegment->OccupiedSize == 0) - MIHP_MergeHeapSegments(segment->PreviousSegment, segment); + MIHP_MergeHeapSegments(heap, segment->PreviousSegment, segment); } MIHP_UnlockHeap(heap); return true; } +bool MIHP_MergeHeaps(MIHP_Heap* sourceHeap, MIHP_Heap* heapToAbsorb) +{ + if (sourceHeap == NULL) + return false; + + if (heapToAbsorb == NULL) + return false; + + if (!MIHP_IsHeapInitialized(sourceHeap)) + return false; + + if (!MIHP_IsHeapInitialized(heapToAbsorb)) + return false; + + if (sourceHeap->Config.PlatformFreeMemoryFn != heapToAbsorb->Config.PlatformFreeMemoryFn) + return false; + + if (sourceHeap->Config.AllocationAlignment != heapToAbsorb->Config.AllocationAlignment) + return false; + + if (sourceHeap->Config.MinimalMemoryAreaSize > heapToAbsorb->Config.MinimalMemoryAreaSize) + return false; + + if (sourceHeap->Config.MaximalMemoryAreaSize < heapToAbsorb->Config.MaximalMemoryAreaSize) + return false; + + MIHP_LockHeap(sourceHeap); + MIHP_LockHeap(heapToAbsorb); + + MIHP_HeapMemoryAreaHeader* sourceEndArea = sourceHeap->FirstArea; + while (true) + { + MIHP_ValidateHeapMemoryAreaHeader(sourceHeap, sourceEndArea); + if (sourceEndArea->NextArea == NULL) + break; + + sourceEndArea = sourceEndArea->NextArea; + } + + sourceEndArea->NextArea = heapToAbsorb->FirstArea; + heapToAbsorb->FirstArea->PreviousArea = sourceEndArea; + + heapToAbsorb->FirstArea = NULL; + + sourceHeap->Stats.NumMemoryAreas += heapToAbsorb->Stats.NumMemoryAreas; + sourceHeap->Stats.NumTotalSegments += heapToAbsorb->Stats.NumTotalSegments; + sourceHeap->Stats.NumTotalOccupiedSegments += heapToAbsorb->Stats.NumTotalOccupiedSegments; + sourceHeap->Stats.TotalSize += heapToAbsorb->Stats.TotalSize; + + MIHP_UnlockHeap(heapToAbsorb); + MIHP_MEMSET(heapToAbsorb, sizeof(MIHP_Heap), 0); + + sourceEndArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(sourceEndArea); + sourceEndArea->NextArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(sourceEndArea->NextArea); + MIHP_UnlockHeap(sourceHeap); + return true; +} + bool MIHP_IsPointerInHeap(MIHP_Heap* heap, void* ptr) { if (heap == NULL) @@ -438,12 +496,12 @@ MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_Heap* heap, size_t req MIHP_ASSERT(actualSize >= effectiveSize); MIHP_MEMSET(area, sizeof(MIHP_HeapMemoryAreaHeader), 0); + area->InstigatingHeap = heap; area->AreaSize = actualSize; - area->OwningHeap = heap; area->Checksum = ~0; size_t headerSize = MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapMemoryAreaHeader)); - area->FirstSegment = MIHP_InitializeHeapSegment(area, (char*)area + headerSize, area->AreaSize - headerSize); + area->FirstSegment = MIHP_InitializeHeapSegment(heap, area, (char*)area + headerSize, area->AreaSize - headerSize); area->FirstSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(area->FirstSegment); heap->Stats.NumMemoryAreas++; @@ -461,7 +519,7 @@ bool MIHP_DestroyHeapMemoryArea(MIHP_Heap* heap, MIHP_HeapMemoryAreaHeader* memo size_t areaNumOccupiedSegments = memoryArea->NumOccupiedSegments; size_t areaSize = memoryArea->AreaSize; - if (!heap->Config.PlatformFreeMemoryFn(heap, memoryArea, memoryArea->AreaSize)) + if (!heap->Config.PlatformFreeMemoryFn(memoryArea->InstigatingHeap, memoryArea, memoryArea->AreaSize)) return false; heap->Stats.NumTotalSegments -= areaNumSegments; @@ -472,7 +530,7 @@ bool MIHP_DestroyHeapMemoryArea(MIHP_Heap* heap, MIHP_HeapMemoryAreaHeader* memo return true; } -MIHP_HeapSegmentHeader* MIHP_InitializeHeapSegment(MIHP_HeapMemoryAreaHeader* area, void* segmentStart, size_t segmentSize) +MIHP_HeapSegmentHeader* MIHP_InitializeHeapSegment(MIHP_Heap* heap, MIHP_HeapMemoryAreaHeader* area, void* segmentStart, size_t segmentSize) { MIHP_ASSERT(area); MIHP_ASSERT(segmentStart); @@ -488,12 +546,12 @@ MIHP_HeapSegmentHeader* MIHP_InitializeHeapSegment(MIHP_HeapMemoryAreaHeader* ar area->NumSegments++; area->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(area); - area->OwningHeap->Stats.NumTotalSegments++; + heap->Stats.NumTotalSegments++; return segment; } -bool MIHP_UninitializeHeapSegment(MIHP_HeapSegmentHeader* segment) +bool MIHP_UninitializeHeapSegment(MIHP_Heap* heap, MIHP_HeapSegmentHeader* segment) { MIHP_ASSERT(segment); @@ -502,19 +560,19 @@ bool MIHP_UninitializeHeapSegment(MIHP_HeapSegmentHeader* segment) segment->OwningMemoryArea->NumSegments--; segment->OwningMemoryArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(segment->OwningMemoryArea); - segment->OwningMemoryArea->OwningHeap->Stats.NumTotalSegments--; + heap->Stats.NumTotalSegments--; MIHP_MEMSET(segment, sizeof(MIHP_HeapSegmentHeader), 0); return true; } -bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegmentMinSize, MIHP_HeapSegmentHeader** outNewSegment) +bool MIHP_SplitHeapSegment(MIHP_Heap* heap, MIHP_HeapSegmentHeader* sourceSegment, size_t newSegmentMinSize, MIHP_HeapSegmentHeader** outNewSegment) { MIHP_ASSERT(sourceSegment); - size_t headerSize = MIHP_GetHeapAlignedSize(sourceSegment->OwningMemoryArea->OwningHeap, sizeof(MIHP_HeapSegmentHeader)); - size_t effectiveNewSegmentSize = MIHP_GetHeapAlignedSize(sourceSegment->OwningMemoryArea->OwningHeap, newSegmentMinSize); + size_t headerSize = MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapSegmentHeader)); + size_t effectiveNewSegmentSize = MIHP_GetHeapAlignedSize(heap, newSegmentMinSize); if (sourceSegment->SegmentSize < effectiveNewSegmentSize) return false; @@ -526,13 +584,13 @@ bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegm sourceSegment->SegmentSize = sourceResultingSegmentSize; - MIHP_HeapSegmentHeader* newSegment = MIHP_InitializeHeapSegment(sourceSegment->OwningMemoryArea, (char*)sourceSegment + sourceResultingSegmentSize, effectiveNewSegmentSize); + MIHP_HeapSegmentHeader* newSegment = MIHP_InitializeHeapSegment(heap, sourceSegment->OwningMemoryArea, (char*)sourceSegment + sourceResultingSegmentSize, effectiveNewSegmentSize); newSegment->NextSegment = sourceSegment->NextSegment; newSegment->PreviousSegment = sourceSegment; if (sourceSegment->NextSegment) { - MIHP_ValidateHeapSegmentHeader(sourceSegment->OwningMemoryArea->OwningHeap, sourceSegment->NextSegment); + MIHP_ValidateHeapSegmentHeader(heap, sourceSegment->NextSegment); sourceSegment->NextSegment->PreviousSegment = newSegment; sourceSegment->NextSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(sourceSegment->NextSegment); } @@ -546,7 +604,7 @@ bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegm return true; } -bool MIHP_MergeHeapSegments(MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegmentHeader* segmentToAbsorb) +bool MIHP_MergeHeapSegments(MIHP_Heap* heap, MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegmentHeader* segmentToAbsorb) { MIHP_ASSERT(sourceSegment); MIHP_ASSERT(segmentToAbsorb); @@ -559,13 +617,13 @@ bool MIHP_MergeHeapSegments(MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegm if (sourceSegment->NextSegment) { - MIHP_ValidateHeapSegmentHeader(sourceSegment->OwningMemoryArea->OwningHeap, sourceSegment->NextSegment); + MIHP_ValidateHeapSegmentHeader(heap, sourceSegment->NextSegment); sourceSegment->NextSegment->PreviousSegment = sourceSegment; sourceSegment->NextSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(sourceSegment->NextSegment); } sourceSegment->SegmentSize += segmentToAbsorb->SegmentSize; - MIHP_UninitializeHeapSegment(segmentToAbsorb); + MIHP_UninitializeHeapSegment(heap, segmentToAbsorb); sourceSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(sourceSegment); diff --git a/minimal_heap_test.c b/minimal_heap_test.c index 59fae10..7e64db4 100644 --- a/minimal_heap_test.c +++ b/minimal_heap_test.c @@ -59,7 +59,7 @@ int main() __debugbreak(); - MIHP_MEMSET(myptrs[5], 5000, 0x75); + //MIHP_MEMSET(myptrs[5], 5000, 0x75); for (int i = 0; i < NUM_ALLOCATIONS; i++) {