From d2cd90fbd718d2ad514c44adc856182d5ecab710 Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Tue, 9 Jun 2026 21:47:40 +0200 Subject: [PATCH] changed all things to function ptr --- minimal_heap.h | 39 +++++++++------- minimal_heap_implementation.inl | 81 +++++++++++++++++++++++---------- minimal_heap_test.c | 13 ++++-- 3 files changed, 90 insertions(+), 43 deletions(-) diff --git a/minimal_heap.h b/minimal_heap.h index 6fe261b..30fda82 100644 --- a/minimal_heap.h +++ b/minimal_heap.h @@ -16,7 +16,6 @@ #define MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_CHECKSUM 2 /* Defines to be configured by the library user */ - #ifndef MIHP_HEAP_STRUCTURE_VALIDATION_TYPE #define MIHP_HEAP_STRUCTURE_VALIDATION_TYPE MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_CHECKSUM #endif @@ -33,31 +32,38 @@ #define MIHP_ASSERT(Condition) while(1) { if (Condition) break; *(volatile char*)(0x0) = 0; } #endif -#ifndef MIHP_HEAP_LOCK_TYPE - #define MIHP_HEAP_LOCK_TYPE bool // Does NOT have to be reentred safe - #define MIHP_LOCK_HEAP(LockVarPtr) {} - #define MIHP_UNLOCK_HEAP(LockVarPtr) {} +#ifndef MIHP_MEMSET + #define MIHP_MEMSET(Ptr, Size, Val) for(size_t i = 0; i < Size; ++i) *((char*)Ptr + i) = Val; #endif /* */ -/* Hooks to be implemented by the library user */ -void* MIHP_PlatformRequestMemory(const struct _MIHP_Heap* heap, size_t minRequestedSize, size_t* outActualSize); // Alignment must at least be alignment of size_t, outActualSize must at least be minRequestedSize -bool MIHP_PlatformFreeMemory(const struct _MIHP_Heap* heap, void* ptr, size_t actualSize); -void MIHP_PlatformOnHeapCorruptionDetected(const struct _MIHP_Heap* heap, struct _MIHP_HeapCorruptionInfo info); -/* */ +typedef void*(MIHP_PlatformReqeustMemoryFn)(const struct _MIHP_Heap* heap, size_t minRequestedSize, size_t* outActualSize); +typedef bool (MIHP_PlatformFreeMemoryFn)(const struct _MIHP_Heap* heap, void* ptr, size_t actualSize); #define MIHP_HEAP_CORRUPTION_TYPE_MEMORY_AREA_CHECKSUM_MISMATCH 0 #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(MIHIP_LockHeapFn)(const struct _MIHP_Heap* heap, void* heapLock); +typedef void(MIHIP_UnlockHeapFn)(const struct _MIHP_Heap* heap, void* heapLock); + typedef struct _MIHP_HeapConfig { - size_t AllocationAlignment; // Must be power of two and at least sizeof(size_t) + MIHP_PlatformReqeustMemoryFn* PlatformRequestMemoryFn; // Alignment must at least be alignment of size_t, outActualSize must at least be minRequestedSize + MIHP_PlatformFreeMemoryFn* PlatformFreeMemoryFn; // Can return false if the memory cannot be freed + MIHP_OnHeapCorruptionDetectedFn* OnHeapCorruptionDetectedFn; // Can be NULL - size_t MinimalMemoryAreaSize; // Must be a multiple of AllocationAlignment - size_t MaximalMemoryAreaSize; // Must be a multiple of AllocationAlignment + size_t MinimalMemoryAreaSize; // Must be a multiple of AllocationAlignment + size_t MaximalMemoryAreaSize; // Must be a multiple of AllocationAlignment - char AllocationInitialValue; + size_t AllocationAlignment; // Must be power of two and at least sizeof(size_t) + char AllocationInitialValue; // Initial value the returned blocks are to be filled with + + void* HeapLock; // Does not need to be reentred safe, can be NULL to disable locking + MIHIP_LockHeapFn* LockHeapFn; // Can be NULL if HeapLock is NULL + MIHIP_LockHeapFn* UnlockHeapFn; // Can be NULL if HeapLock is NULL } MIHP_HeapConfig; typedef struct _MIHP_HeapStats @@ -114,8 +120,6 @@ typedef struct _MIHP_Heap MIHP_HeapStats Stats; MIHP_HeapMemoryAreaHeader* FirstArea; MIHP_HeapMemoryAreaHeader* LastSuccessfulAllocationArea; - - MIHP_HEAP_LOCK_TYPE HeapLock; } MIHP_Heap; /* API Interface */ @@ -133,6 +137,9 @@ void MIHP_ValidateHeap(MIHP_Heap* heap); /* */ /* Internals */ +void MIHP_LockHeap(MIHP_Heap* heap); +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); diff --git a/minimal_heap_implementation.inl b/minimal_heap_implementation.inl index dc065c9..fc3b80c 100644 --- a/minimal_heap_implementation.inl +++ b/minimal_heap_implementation.inl @@ -1,8 +1,6 @@ #define MIHP_MIN(A, B) (A) < (B) ? (A) : (B) #define MIHP_MAX(A, B) (A) > (B) ? (A) : (B) -#define MIHP_MEMSET(Ptr, Size, Val) for(size_t i = 0; i < Size; ++i) *((char*)Ptr + i) = Val; - #define MIHP_IS_PO2(Val) (Val != 0 && (Val & (Val - 1)) == 0) bool MIHP_InitializeHeap(MIHP_Heap* heap, MIHP_HeapConfig config) @@ -13,6 +11,12 @@ bool MIHP_InitializeHeap(MIHP_Heap* heap, MIHP_HeapConfig config) if (MIHP_IsHeapInitialized(heap)) return false; + if (config.PlatformRequestMemoryFn == NULL) + return false; + + if (config.PlatformFreeMemoryFn == NULL) + return false; + if (config.AllocationAlignment < sizeof(size_t)) return false; @@ -25,6 +29,15 @@ bool MIHP_InitializeHeap(MIHP_Heap* heap, MIHP_HeapConfig config) if (config.MaximalMemoryAreaSize % config.AllocationAlignment != 0) return false; + if (config.HeapLock != NULL) + { + if (config.LockHeapFn == NULL) + return false; + + if (config.UnlockHeapFn == NULL) + return false; + } + MIHP_MEMSET(heap, sizeof(MIHP_Heap), 0); heap->Config = config; @@ -79,7 +92,7 @@ void* MIHP_Allocate(MIHP_Heap* heap, size_t size) if (size > heap->Config.MaximalMemoryAreaSize) return NULL; - MIHP_LOCK_HEAP(&heap->HeapLock); + MIHP_LockHeap(heap); MIHP_HeapMemoryAreaHeader* nextArea = heap->FirstArea; do @@ -133,7 +146,7 @@ void* MIHP_Allocate(MIHP_Heap* heap, size_t size) heap->Stats.NumTotalOccupiedSegments++; heap->LastSuccessfulAllocationArea = currentArea; - MIHP_UNLOCK_HEAP(&heap->HeapLock); + MIHP_UnlockHeap(heap); void* data = MIHP_GetSegmentPayloadPtr(heap, targetSegment); MIHP_MEMSET(data, size, heap->Config.AllocationInitialValue); @@ -152,7 +165,7 @@ void* MIHP_Allocate(MIHP_Heap* heap, size_t size) MIHP_HeapMemoryAreaHeader* newArea = MIHP_CreateHeapMemoryArea(heap, newAreaSize); if (newArea == NULL) { - MIHP_UNLOCK_HEAP(&heap->HeapLock); + MIHP_UnlockHeap(heap); return NULL; } @@ -164,7 +177,7 @@ void* MIHP_Allocate(MIHP_Heap* heap, size_t size) heap->LastSuccessfulAllocationArea = newArea; newArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(newArea); - MIHP_UNLOCK_HEAP(&heap->HeapLock); + MIHP_UnlockHeap(heap); return MIHP_Allocate(heap, size); } @@ -185,7 +198,7 @@ void* MIHP_Reallocate(MIHP_Heap* heap, void* ptr, size_t newSize) if (!MIHP_IsPointerInHeap(heap, ptr)) return NULL; - MIHP_LOCK_HEAP(&heap->HeapLock); + MIHP_LockHeap(heap); MIHP_HeapSegmentHeader* segment = MIHP_GetSegmentHeaderPtr(heap, ptr); MIHP_ValidateHeapSegmentHeader(heap, segment); @@ -200,17 +213,17 @@ void* MIHP_Reallocate(MIHP_Heap* heap, void* ptr, size_t newSize) segment->OccupiedSize = newSize; segment->Checksum = MIHP_GenerateHeapSegmentChecksum(segment); - MIHP_UNLOCK_HEAP(&heap->HeapLock); + MIHP_UnlockHeap(heap); return ptr; } if (segment->NextSegment && MIHP_MergeHeapSegments(segment, segment->NextSegment)) { - MIHP_UNLOCK_HEAP(&heap->HeapLock); + MIHP_UnlockHeap(heap); return MIHP_Reallocate(heap, ptr, newSize); } - MIHP_UNLOCK_HEAP(&heap->HeapLock); + MIHP_UnlockHeap(heap); void* newPtr = MIHP_Allocate(heap, newSize); if (!newPtr) @@ -238,11 +251,11 @@ void* MIHP_Reallocate(MIHP_Heap* heap, void* ptr, size_t newSize) MIHP_MergeHeapSegments(newSpittedSegment, newSpittedSegment->NextSegment); } - MIHP_UNLOCK_HEAP(&heap->HeapLock); + MIHP_UnlockHeap(heap); return ptr; } - MIHP_UNLOCK_HEAP(&heap->HeapLock); + MIHP_UnlockHeap(heap); return ptr; } @@ -257,7 +270,7 @@ bool MIHP_Free(MIHP_Heap* heap, void* ptr) if (!MIHP_IsPointerInHeap(heap, ptr)) return false; - MIHP_LOCK_HEAP(&heap->HeapLock); + MIHP_LockHeap(heap); MIHP_HeapSegmentHeader* segment = MIHP_GetSegmentHeaderPtr(heap, ptr); MIHP_ValidateHeapSegmentHeader(heap, segment); @@ -271,7 +284,8 @@ bool MIHP_Free(MIHP_Heap* heap, void* ptr) corruptionInfo.Type = MIHP_HEAP_CORRUPTION_TYPE_DOUBLE_FREE; corruptionInfo.Ptr = ptr; - MIHP_PlatformOnHeapCorruptionDetected(heap, corruptionInfo); + if (heap->Config.OnHeapCorruptionDetectedFn != NULL) + heap->Config.OnHeapCorruptionDetectedFn(heap, corruptionInfo); return false; } @@ -310,7 +324,7 @@ bool MIHP_Free(MIHP_Heap* heap, void* ptr) if (heap->LastSuccessfulAllocationArea == area) heap->LastSuccessfulAllocationArea = nextArea; - MIHP_UNLOCK_HEAP(&heap->HeapLock); + MIHP_UnlockHeap(heap); return true; } } @@ -329,7 +343,7 @@ bool MIHP_Free(MIHP_Heap* heap, void* ptr) MIHP_MergeHeapSegments(segment->PreviousSegment, segment); } - MIHP_UNLOCK_HEAP(&heap->HeapLock); + MIHP_UnlockHeap(heap); return true; } @@ -338,7 +352,7 @@ bool MIHP_IsPointerInHeap(MIHP_Heap* heap, void* ptr) if (heap == NULL) return false; - MIHP_LOCK_HEAP(&heap->HeapLock); + MIHP_LockHeap(heap); size_t searchingPtr = (size_t)ptr; @@ -346,6 +360,7 @@ bool MIHP_IsPointerInHeap(MIHP_Heap* heap, void* ptr) while (nextArea) { MIHP_HeapMemoryAreaHeader* currentArea = nextArea; + MIHP_ValidateHeapSegmentHeader(heap, currentArea); nextArea = currentArea->NextArea; size_t ptrMin = (size_t)currentArea; @@ -353,12 +368,12 @@ bool MIHP_IsPointerInHeap(MIHP_Heap* heap, void* ptr) if (searchingPtr >= ptrMin && searchingPtr <= ptrMax) { - MIHP_UNLOCK_HEAP(&heap->HeapLock); + MIHP_UnlockHeap(heap); return true; } } - MIHP_UNLOCK_HEAP(&heap->HeapLock); + MIHP_UnlockHeap(heap); return false; } @@ -367,7 +382,7 @@ size_t MIHP_GetPtrAllocationSize(MIHP_Heap* heap, void* ptr) if (!MIHP_IsPointerInHeap(heap, ptr)) return 0; - MIHP_LOCK_HEAP(&heap->HeapLock); + MIHP_LockHeap(heap); size_t segmentHeaderSize = MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapSegmentHeader)); MIHP_HeapSegmentHeader* segment = (MIHP_HeapSegmentHeader*)((char*)ptr - segmentHeaderSize); @@ -395,6 +410,18 @@ void MIHP_ValidateHeap(MIHP_Heap* heap) } } +void MIHP_LockHeap(MIHP_Heap* heap) +{ + if (heap->Config.HeapLock) + heap->Config.LockHeapFn(heap, heap->Config.HeapLock); +} + +void MIHP_UnlockHeap(MIHP_Heap* heap) +{ + if (heap->Config.HeapLock) + heap->Config.UnlockHeapFn(heap, heap->Config.HeapLock); +} + MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_Heap* heap, size_t requestedSize) { MIHP_ASSERT(heap); @@ -404,7 +431,7 @@ MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_Heap* heap, size_t req effectiveSize = MIHP_MIN(effectiveSize, heap->Config.MaximalMemoryAreaSize); size_t actualSize = 0; - MIHP_HeapMemoryAreaHeader* area = (MIHP_HeapMemoryAreaHeader*)MIHP_PlatformRequestMemory(heap, effectiveSize, &actualSize); + MIHP_HeapMemoryAreaHeader* area = (MIHP_HeapMemoryAreaHeader*)heap->Config.PlatformRequestMemoryFn(heap, effectiveSize, &actualSize); if (area == NULL) return NULL; @@ -434,7 +461,7 @@ bool MIHP_DestroyHeapMemoryArea(MIHP_Heap* heap, MIHP_HeapMemoryAreaHeader* memo size_t areaNumOccupiedSegments = memoryArea->NumOccupiedSegments; size_t areaSize = memoryArea->AreaSize; - if (!MIHP_PlatformFreeMemory(heap, memoryArea, memoryArea->AreaSize)) + if (!heap->Config.PlatformFreeMemoryFn(heap, memoryArea, memoryArea->AreaSize)) return false; heap->Stats.NumTotalSegments -= areaNumSegments; @@ -620,6 +647,9 @@ uint32_t MIHP_GenerateHeapSegmentChecksum(const MIHP_HeapSegmentHeader* segment) void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_Heap* heap, const MIHP_HeapMemoryAreaHeader* area) { + if (heap->Config.OnHeapCorruptionDetectedFn == NULL) + return; + uint32_t newChecksum; #if MIHP_HEAP_STRUCTURE_VALIDATION_TYPE == MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_NONE @@ -640,12 +670,15 @@ void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_Heap* heap, const MIHP_HeapMem corruptionInfo.ExpectedValue = area->Checksum; corruptionInfo.ActualValue = newChecksum; - MIHP_PlatformOnHeapCorruptionDetected(heap, corruptionInfo); + heap->Config.OnHeapCorruptionDetectedFn(heap, corruptionInfo); } } void MIHP_ValidateHeapSegmentHeader(const MIHP_Heap* heap, const MIHP_HeapSegmentHeader* segment) { + if (heap->Config.OnHeapCorruptionDetectedFn == NULL) + return; + uint32_t newChecksum; #if MIHP_HEAP_STRUCTURE_VALIDATION_TYPE == MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_NONE @@ -666,7 +699,7 @@ void MIHP_ValidateHeapSegmentHeader(const MIHP_Heap* heap, const MIHP_HeapSegmen corruptionInfo.ExpectedValue = segment->Checksum; corruptionInfo.ActualValue = newChecksum; - MIHP_PlatformOnHeapCorruptionDetected(heap, corruptionInfo); + heap->Config.OnHeapCorruptionDetectedFn(heap, corruptionInfo); } } diff --git a/minimal_heap_test.c b/minimal_heap_test.c index 67b41fa..59fae10 100644 --- a/minimal_heap_test.c +++ b/minimal_heap_test.c @@ -9,19 +9,19 @@ //#define MIHP_ValidateHeap(x) -void* MIHP_PlatformRequestMemory(const MIHP_Heap* heap, size_t minRequestedSize, size_t* outActualSize) +void* RequestMemory(const MIHP_Heap* heap, size_t minRequestedSize, size_t* outActualSize) { *outActualSize = minRequestedSize; return malloc(minRequestedSize); } -bool MIHP_PlatformFreeMemory(const MIHP_Heap* heap, void* ptr, size_t actualSize) +bool FreeMemory(const MIHP_Heap* heap, void* ptr, size_t actualSize) { free(ptr); return true; } -void MIHP_PlatformOnHeapCorruptionDetected(const MIHP_Heap* heap, MIHP_HeapCorruptionInfo info) +void OnHeapCorruptionDetectedCallback(const MIHP_Heap* heap, MIHP_HeapCorruptionInfo info) { __debugbreak(); } @@ -33,6 +33,11 @@ void* myptrs[NUM_ALLOCATIONS] = { 0 }; int main() { MIHP_HeapConfig config = {0}; + + config.PlatformRequestMemoryFn = RequestMemory; + config.PlatformFreeMemoryFn = FreeMemory; + config.OnHeapCorruptionDetectedFn = OnHeapCorruptionDetectedCallback; + config.AllocationInitialValue = 0xbe; config.AllocationAlignment = 16; config.MinimalMemoryAreaSize = 4096 * 32; @@ -54,6 +59,8 @@ int main() __debugbreak(); + MIHP_MEMSET(myptrs[5], 5000, 0x75); + for (int i = 0; i < NUM_ALLOCATIONS; i++) { if (rand() % 3 == 0)