From 16a390797c72d2762966f9525c48293f001ae0c3 Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Mon, 8 Jun 2026 03:40:22 +0200 Subject: [PATCH 01/19] dev --- minimal_heap.c | 314 ++++++++++++++++++++++++++++++ minimal_heap.h | 171 ++++++++-------- minimal_heap_test.c | 26 +++ minimal_heap_test.sln | 31 +++ minimal_heap_test.vcxproj | 136 +++++++++++++ minimal_heap_test.vcxproj.filters | 30 +++ minimal_heap_test.vcxproj.user | 6 + 7 files changed, 634 insertions(+), 80 deletions(-) create mode 100644 minimal_heap.c create mode 100644 minimal_heap_test.c create mode 100644 minimal_heap_test.sln create mode 100644 minimal_heap_test.vcxproj create mode 100644 minimal_heap_test.vcxproj.filters create mode 100644 minimal_heap_test.vcxproj.user diff --git a/minimal_heap.c b/minimal_heap.c new file mode 100644 index 0000000..9bcf359 --- /dev/null +++ b/minimal_heap.c @@ -0,0 +1,314 @@ +#include "minimal_heap.h" + +#define MIHP_MIN(A, B) (A) < (B) ? (A) : (B) +#define MIHP_MAX(A, B) (A) > (B) ? (A) : (B) + +MIHP_HeapInfo* MIHP_CreateHeap(size_t initialSize, size_t allocationAlignment) +{ + MIHP_HeapInfo* heap = (MIHP_HeapInfo*)MIHP_PlatformRequestMemory(sizeof(MIHP_HeapInfo)); + if (heap == NULL) + return NULL; + + heap->FirstArea = MIHP_CreateHeapMemoryArea(heap, initialSize); + if (heap->FirstArea == NULL) + { + MIHP_PlatformFreeMemory(heap, sizeof(MIHP_HeapInfo)); + return NULL; + } + + heap->AllocationAlignment = allocationAlignment; + return heap; +} + +bool MIHP_DestroyHeap(MIHP_HeapInfo* heap, bool force) +{ + MIHP_ASSERT(heap); + + if (!force && heap->Stats.NumTotalOccupiedSegments > 0) + return false; + + MIHP_HeapMemoryAreaHeader* nextArea = heap->FirstArea; + while (nextArea) + { + MIHP_HeapMemoryAreaHeader* currentArea = nextArea; + nextArea = currentArea->NextArea; + MIHP_DestroyHeapMemoryArea(heap, currentArea); + } + + MIHP_PlatformFreeMemory(heap, sizeof(MIHP_HeapInfo)); + return true; +} + +void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size) +{ + return NULL; +} + +void* MIHP_Realloc(MIHP_HeapInfo* heap, void* ptr, size_t newSize) +{ + return NULL; +} + +void MIHP_Free(MIHP_HeapInfo* heap, void* ptr) +{ +} + +bool MIHP_IsPointerInHeap(MIHP_HeapInfo* heap, void* ptr) +{ + MIHP_LOCK_HEAP(&heap->HeapLock); + + size_t searchingPtr = (size_t)ptr; + + MIHP_HeapMemoryAreaHeader* nextArea = heap->FirstArea; + while (nextArea) + { + MIHP_HeapMemoryAreaHeader* currentArea = nextArea; + nextArea = currentArea->NextArea; + + size_t ptrMin = (size_t)currentArea; + size_t ptrMax = (size_t)currentArea + currentArea->AreaSize; + + if (searchingPtr >= ptrMin && searchingPtr <= ptrMax) + { + MIHP_UNLOCK_HEAP(&heap->HeapLock); + return true; + } + } + + MIHP_UNLOCK_HEAP(&heap->HeapLock); + return false; +} + +void MIHP_ValidateHeap(MIHP_HeapInfo* heap) +{ +} + +MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_HeapInfo* heap, size_t requestedSize) +{ + MIHP_ASSERT(heap); + + size_t effectiveSize = ((requestedSize + MIHP_MINIMAL_MEMORY_AREA_SIZE - 1) / MIHP_MINIMAL_MEMORY_AREA_SIZE) * MIHP_MINIMAL_MEMORY_AREA_SIZE; + + MIHP_HeapMemoryAreaHeader* area = MIHP_PlatformRequestMemory(effectiveSize); + if (area == NULL) + return NULL; + + heap->Stats.NumMemoryAreas++; + area->NextArea = NULL; + area->PreviousArea = NULL; + area->AreaSize = effectiveSize; + area->NumOccupiedSegments = 0; + area->NumSegments = 0; + area->OwningHeap = heap; + + size_t headerSize = MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapMemoryAreaHeader)); + area->FirstSegment = MIHP_InitializeHeapSegment(area, (char*)area + headerSize, area->AreaSize - headerSize); + + area->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(area); + + return area; +} + +bool MIHP_DestroyHeapMemoryArea(MIHP_HeapInfo* heap, MIHP_HeapMemoryAreaHeader* memoryArea) +{ + MIHP_ASSERT(heap); + MIHP_ASSERT(memoryArea); + + size_t areaNumSegments = memoryArea->NumSegments; + size_t areaNumOccupiedSegments = memoryArea->NumOccupiedSegments; + + if (!MIHP_PlatformFreeMemory(memoryArea, memoryArea->AreaSize)) + return false; + + heap->Stats.NumTotalSegments -= areaNumSegments; + heap->Stats.NumTotalOccupiedSegments -= areaNumOccupiedSegments; + heap->Stats.NumMemoryAreas--; + return true; +} + +MIHP_HeapSegmentHeader* MIHP_InitializeHeapSegment(MIHP_HeapMemoryAreaHeader* area, void* segmentStart, size_t segmentSize) +{ + MIHP_ASSERT(area); + MIHP_ASSERT(segmentStart); + + MIHP_HeapSegmentHeader* segment = (MIHP_HeapSegmentHeader*)segmentStart; + segment->SegmentSize = segmentSize; + segment->OccupiedSize = 0; + segment->NextSegment = NULL; + segment->PreviousSegment = NULL; + segment->OwningMemoryArea = area; + + segment->Checksum = MIHP_GenerateHeapSegmentChecksum(segment); + + area->NumSegments++; + area->OwningHeap->Stats.NumTotalSegments++; + return segment; +} + +bool MIHP_UninitializeHeapSegment(MIHP_HeapSegmentHeader* segment) +{ + MIHP_ASSERT(segment); + + if (segment->OccupiedSize > 0) + return false; + + segment->OwningMemoryArea->NumSegments--; + segment->OwningMemoryArea->OwningHeap->Stats.NumTotalSegments--; + +#if MIHP_ZERO_OUT_MERGED_HEADERS + segment->SegmentSize = 0; + segment->OccupiedSize = 0; + segment->NextSegment = NULL; + segment->PreviousSegment = NULL; + segment->OwningMemoryArea = NULL; + segment->Checksum = 0; +#endif + + return true; +} + +bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegmentMinSize, MIHP_HeapSegmentHeader** outNewSegment) +{ + MIHP_ASSERT(sourceSegment); + MIHP_ValidateHeapSegmentHeader(sourceSegment); + MIHP_ValidateHeapMemoryAreaHeader(sourceSegment->OwningMemoryArea); + + size_t headerSize = MIHP_GetHeapAlignedSize(sourceSegment->OwningMemoryArea->OwningHeap, sizeof(MIHP_HeapSegmentHeader)); + size_t effectiveNewSegmentSize = MIHP_GetHeapAlignedSize(sourceSegment->OwningMemoryArea->OwningHeap, newSegmentMinSize); + + if (sourceSegment->SegmentSize < effectiveNewSegmentSize) + return false; + + size_t sourceResultingSegmentSize = sourceSegment->SegmentSize - effectiveNewSegmentSize; + + if (sourceResultingSegmentSize < sourceSegment->OccupiedSize + headerSize) + return false; + + sourceSegment->SegmentSize = sourceResultingSegmentSize; + + MIHP_HeapSegmentHeader* newSegment = MIHP_InitializeHeapSegment(sourceSegment->OwningMemoryArea, (char*)sourceSegment + sourceResultingSegmentSize, effectiveNewSegmentSize); + newSegment->NextSegment = sourceSegment->NextSegment; + newSegment->PreviousSegment = sourceSegment; + + if (sourceSegment->NextSegment) + sourceSegment->NextSegment->PreviousSegment = newSegment; + + sourceSegment->NextSegment = newSegment; + + if (outNewSegment) + *outNewSegment = newSegment; + + newSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(newSegment); + sourceSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(sourceSegment); + + return true; +} + +bool MIHP_MergeHeapSegments(MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegmentHeader* segmentToAbsorb) +{ + MIHP_ASSERT(sourceSegment); + MIHP_ASSERT(segmentToAbsorb); + MIHP_ASSERT(sourceSegment->NextSegment == segmentToAbsorb); + + MIHP_ValidateHeapSegmentHeader(sourceSegment); + MIHP_ValidateHeapSegmentHeader(segmentToAbsorb); + MIHP_ValidateHeapMemoryAreaHeader(segmentToAbsorb->OwningMemoryArea); + + if (segmentToAbsorb->OccupiedSize > 0) + return false; + + sourceSegment->NextSegment = segmentToAbsorb->NextSegment; + + if (sourceSegment->NextSegment) + sourceSegment->NextSegment->PreviousSegment = sourceSegment; + + sourceSegment->SegmentSize += segmentToAbsorb->SegmentSize; + MIHP_UninitializeHeapSegment(segmentToAbsorb); + + return true; +} + +size_t MIHP_GetHeapAlignedSize(MIHP_HeapInfo* heap, size_t size) +{ + return (size + (heap->AllocationAlignment - 1)) & ~(heap->AllocationAlignment - 1); +} + +uint32_t MIHP_HashMemoryRegion(const void* data, size_t size) +{ + uint32_t hash = 2166136261U; + const unsigned char* bytes = (const unsigned char*)data; + for (size_t i = 0; i < size; i++) + { + hash ^= bytes[i]; + hash *= 16777619U; + } + + return hash; +} + +uint32_t MIHP_GenerateHeapMemoryAreaChecksum(const MIHP_HeapMemoryAreaHeader* area) +{ +#if !MIHP_USE_HEAP_STRUCTURE_CHECKSUM_VALIDATION + return 0; +#endif + + MIHP_ASSERT(area); + + // Do not include the checksum itself into the new checksum + size_t size = sizeof(MIHP_HeapMemoryAreaHeader) - sizeof(area->Checksum); + return MIHP_HashMemoryRegion(area, size); +} + +uint32_t MIHP_GenerateHeapSegmentChecksum(const MIHP_HeapSegmentHeader* segment) +{ +#if !MIHP_USE_HEAP_STRUCTURE_CHECKSUM_VALIDATION + return 0; +#endif + + MIHP_ASSERT(segment); + + // Do not include the checksum itself into the new checksum + size_t size = sizeof(MIHP_HeapSegmentHeader) - sizeof(segment->Checksum); + return MIHP_HashMemoryRegion(segment, size); +} + +void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_HeapMemoryAreaHeader* area) +{ +#if !MIHP_USE_HEAP_STRUCTURE_CHECKSUM_VALIDATION + return; +#endif + + size_t newChecksum = MIHP_GenerateHeapMemoryAreaChecksum(area); + + if (area->Checksum != newChecksum) + { + MIHP_HeapCorruptionInfo corruptionInfo; + corruptionInfo.Type = MIHP_HEAP_CORRUPTION_TYPE_MEMORY_AREA_CHECKSUM_MISMATCH; + corruptionInfo.Ptr = area; + corruptionInfo.ExpectedValue = area->Checksum; + corruptionInfo.ActualValue = newChecksum; + + MIHP_PlatformOnHeapCorruptionDetected(corruptionInfo); + } +} + +void MIHP_ValidateHeapSegmentHeader(const MIHP_HeapSegmentHeader* segment) +{ +#if !MIHP_USE_HEAP_STRUCTURE_CHECKSUM_VALIDATION + return; +#endif + + size_t newChecksum = MIHP_GenerateHeapSegmentChecksum(segment); + + if (segment->Checksum != newChecksum) + { + MIHP_HeapCorruptionInfo corruptionInfo; + corruptionInfo.Type = MIHP_HEAP_CORRUPTION_TYPE_SEGMENT_CHECKSUM_MISMATCH; + corruptionInfo.Ptr = segment; + corruptionInfo.ExpectedValue = segment->Checksum; + corruptionInfo.ActualValue = newChecksum; + + MIHP_PlatformOnHeapCorruptionDetected(corruptionInfo); + } +} + diff --git a/minimal_heap.h b/minimal_heap.h index 20a5dab..86c0435 100644 --- a/minimal_heap.h +++ b/minimal_heap.h @@ -4,107 +4,118 @@ #include #include -#define USE_HEAP_STRUCTURE_CHECKSUM 1 -#define USE_CANARY_VALIDATION 1 +#define MIHP_USE_HEAP_STRUCTURE_CHECKSUM_VALIDATION 1 +#define MIHP_USE_CANARY_VALIDATION 1 -#define HEAP_CORRUPTION_TYPE_MEMORY_AREA_CHECKSUM_MISMATCH 0 -#define HEAP_CORRUPTION_TYPE_SEGMENT_CHECKSUM_MISMATCH 1 -#define HEAP_CORRUPTION_TYPE_FRONT_CANARY_MISMATCH 2 -#define HEAP_CORRUPTION_TYPE_REAR_CANARY_MISMATCH 3 +#define MIHP_ZERO_OUT_MERGED_HEADERS 1 +#define MIHP_ZERO_OUT_ALLOCATIONS 1 -struct heap_stats +#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 + +typedef struct _MIHP_HeapStats { - size_t num_memory_areas; - size_t num_total_segments; - size_t num_total_occupied_segments; - size_t total_size; -} typedef heap_stats; + size_t NumMemoryAreas; + size_t NumTotalSegments; + size_t NumTotalOccupiedSegments; + size_t TotalSize; +} MIHP_HeapStats; -struct heap_memory_area +// This structs size must be multiple of 8 +typedef struct _MIHP_HeapMemoryAreaHeader { - size_t size; - size_t num_segments; - size_t num_occupied_segments; - heap_memory_area* next_area; - heap_memory_area* previous_area; + size_t AreaSize; + size_t NumSegments; + size_t NumOccupiedSegments; -#if USE_HEAP_STRUCTURE_CHECKSUM - uint32_t checksum; -#endif -} typedef heap_memory_area; + struct _MIHP_HeapMemoryAreaHeader* NextArea; + struct _MIHP_HeapMemoryAreaHeader* PreviousArea; -struct heap_segment + struct _MIHP_HeapInfo* OwningHeap; + struct _MIHP_HeapSegmentHeader* FirstSegment; + + + uint32_t Checksum; // Checksum must be the last member ! +} MIHP_HeapMemoryAreaHeader; + +// This structs size must be multiple of 8 +typedef struct _MIHP_HeapSegmentHeader { - size_t size; - bool is_occupied; + size_t SegmentSize; + size_t OccupiedSize; - heap_segment* next_segment; - heap_segment* previous_segment; - heap_memory_area* encapsulating_memory_area; + struct _MIHP_HeapSegmentHeader* NextSegment; + struct _MIHP_HeapSegmentHeader* PreviousSegment; + struct _MIHP_HeapMemoryAreaHeader* OwningMemoryArea; -#if USE_HEAP_STRUCTURE_CHECKSUM - uint32_t checksum; -#endif -} typedef heap_segment; + char _padding0[16]; -struct heap_corruption_info + uint32_t Checksum; // Checksum must be the last member ! + +} MIHP_HeapSegmentHeader; + +typedef struct _MIHP_HeapCorruptionInfo { - uint8_t type; - void* ptr; - uint32_t expected_value; - uint32_t actual_value; -} typedef heap_corruption_info; + uint8_t Type; + const void* Ptr; + uint32_t ExpectedValue; + uint32_t ActualValue; +} MIHP_HeapCorruptionInfo; /* Hooks to be implemented by the library user */ -void* platform_request_memory_area(size_t size); -bool platform_free_memory_area(void* ptr, size_t size); -uint8_t platform_get_required_memory_alingment(); -void platform_heap_corruption_detected(heap_corruption_info info); - -size_t config_minimal_memory_area_size(); -size_t config_minimal_amount_unoccupied_bytes(); -size_t config_minimal_amount_unoccupied_continuous_bytes(); +void* MIHP_PlatformRequestMemory(size_t size); // Alignment must at least be alingment of size_t +bool MIHP_PlatformFreeMemory(void* ptr, size_t size); +void MIHP_PlatformOnHeapCorruptionDetected(MIHP_HeapCorruptionInfo info); /* === */ -uint32_t fast_memory_hasher(const void* data, size_t size) +/* Defines to be configured by the library user */ +#define MIHP_MINIMAL_MEMORY_AREA_SIZE (4096 * 32) + +#define MIHP_ASSERT(Condition) do { if (Condition) break; *(volatile char*)(0x0) = 0; } while(1) + +#define MIHP_HEAP_LOCK_TYPE uint8_t +#define MIHP_LOCK_HEAP(LockVariablePtr) {} +#define MIHP_UNLOCK_HEAP(LockVarialbePtr) {} +/* === */ + +typedef struct _MIHP_HeapInfo { - uint32_t hash = 2166136261U; - const unsigned char* bytes = (const unsigned char*)data; - for (size_t i = 0; i < size; i++) - { - hash ^= bytes[i]; - hash *= 16777619U; - } + MIHP_HeapStats Stats; + size_t AllocationAlignment; + MIHP_HeapMemoryAreaHeader* FirstArea; - return hash; -} + MIHP_HEAP_LOCK_TYPE HeapLock; +} MIHP_HeapInfo; -uint32_t generate_heap_memory_area_checksum(const heap_memory_area* area) -{ - size_t checksum_size; +/* API Interface */ +MIHP_HeapInfo* MIHP_CreateHeap(size_t initialSize, size_t allocationAlignment); +bool MIHP_DestroyHeap(MIHP_HeapInfo* heap, bool force); +void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size); +void* MIHP_Realloc(MIHP_HeapInfo* heap, void* ptr, size_t newSize); +void MIHP_Free(MIHP_HeapInfo* heap, void* ptr); -#if USE_HEAP_STRUCTURE_CHECKSUM - checksum_size = sizeof(area->checksum); -#else - checksum_size = 0; -#endif +bool MIHP_IsPointerInHeap(MIHP_HeapInfo* heap, void* ptr); +void MIHP_ValidateHeap(MIHP_HeapInfo* heap); +/* */ - // Do not include the checksum itself into the new checksum - size_t size = sizeof(*area) - checksum_size; - return fast_memory_hasher(area, size); -} +/* Internals */ +MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_HeapInfo* heap, size_t requestedSize); +bool MIHP_DestroyHeapMemoryArea(MIHP_HeapInfo* heap, MIHP_HeapMemoryAreaHeader* area); -uint32_t generate_heap_segment_checksum(const heap_segment* segment) -{ - size_t checksum_size; +MIHP_HeapSegmentHeader* MIHP_InitializeHeapSegment(MIHP_HeapMemoryAreaHeader* area, void* segmentStart, size_t size); +bool MIHP_UninitializeHeapSegment(MIHP_HeapSegmentHeader* segment); -#if USE_HEAP_STRUCTURE_CHECKSUM - checksum_size = sizeof(segment->checksum); -#else - checksum_size = 0; -#endif +bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegmentSize, MIHP_HeapSegmentHeader** outNewSegment); +bool MIHP_MergeHeapSegments(MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegmentHeader* segmentToAbsorb); - // Do not include the checksum itself into the new checksum - size_t size = sizeof(*segment) - checksum_size; - return fast_memory_hasher(segment, size); -} \ No newline at end of file +size_t MIHP_GetHeapAlignedSize(MIHP_HeapInfo* heap, size_t size); + +uint32_t MIHP_HashMemoryRegion(const void* data, size_t size); +uint32_t MIHP_GenerateHeapMemoryAreaChecksum(const MIHP_HeapMemoryAreaHeader* area); +uint32_t MIHP_GenerateHeapSegmentChecksum(const MIHP_HeapSegmentHeader* segment); + +void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_HeapMemoryAreaHeader* area); +void MIHP_ValidateHeapSegmentHeader(const MIHP_HeapSegmentHeader* segment); +/* */ diff --git a/minimal_heap_test.c b/minimal_heap_test.c new file mode 100644 index 0000000..4e76e6e --- /dev/null +++ b/minimal_heap_test.c @@ -0,0 +1,26 @@ +#include "minimal_heap.h" + +void* MIHP_PlatformRequestMemory(size_t size) +{ + +} + +bool MIHP_PlatformFreeMemory(void* ptr, size_t size) +{ + +} + +uint8_t MIHP_PlatformGetMinimalMemoryAlignment() +{ + +} + +void MIHP_PlatformOnHeapCorruptionDetected(MIHP_HeapCorruptionInfo info) +{ + +} + +int main() +{ +} + diff --git a/minimal_heap_test.sln b/minimal_heap_test.sln new file mode 100644 index 0000000..806e01c --- /dev/null +++ b/minimal_heap_test.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36717.8 d17.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minimal_heap_test", "minimal_heap_test.vcxproj", "{58F662F6-EAAC-4D4B-A2F5-C25ED48A05F7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {58F662F6-EAAC-4D4B-A2F5-C25ED48A05F7}.Debug|x64.ActiveCfg = Debug|x64 + {58F662F6-EAAC-4D4B-A2F5-C25ED48A05F7}.Debug|x64.Build.0 = Debug|x64 + {58F662F6-EAAC-4D4B-A2F5-C25ED48A05F7}.Debug|x86.ActiveCfg = Debug|Win32 + {58F662F6-EAAC-4D4B-A2F5-C25ED48A05F7}.Debug|x86.Build.0 = Debug|Win32 + {58F662F6-EAAC-4D4B-A2F5-C25ED48A05F7}.Release|x64.ActiveCfg = Release|x64 + {58F662F6-EAAC-4D4B-A2F5-C25ED48A05F7}.Release|x64.Build.0 = Release|x64 + {58F662F6-EAAC-4D4B-A2F5-C25ED48A05F7}.Release|x86.ActiveCfg = Release|Win32 + {58F662F6-EAAC-4D4B-A2F5-C25ED48A05F7}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4273B178-AE5C-4FCB-99D3-ACA9EE4C7E80} + EndGlobalSection +EndGlobal diff --git a/minimal_heap_test.vcxproj b/minimal_heap_test.vcxproj new file mode 100644 index 0000000..9688f30 --- /dev/null +++ b/minimal_heap_test.vcxproj @@ -0,0 +1,136 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {58f662f6-eaac-4d4b-a2f5-c25ed48a05f7} + minimalheaptest + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdc17 + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/minimal_heap_test.vcxproj.filters b/minimal_heap_test.vcxproj.filters new file mode 100644 index 0000000..e9330a5 --- /dev/null +++ b/minimal_heap_test.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Quelldateien + + + Quelldateien + + + + + Headerdateien + + + \ No newline at end of file diff --git a/minimal_heap_test.vcxproj.user b/minimal_heap_test.vcxproj.user new file mode 100644 index 0000000..966b4ff --- /dev/null +++ b/minimal_heap_test.vcxproj.user @@ -0,0 +1,6 @@ + + + + true + + \ No newline at end of file From e7d304ba353a405aaa3df53253c95d60c8070dcb Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Mon, 8 Jun 2026 04:30:08 +0200 Subject: [PATCH 02/19] allocate --- minimal_heap.c | 121 ++++++++++++++++++++++++++++++++++++++++++------- minimal_heap.h | 14 ++++-- 2 files changed, 116 insertions(+), 19 deletions(-) diff --git a/minimal_heap.c b/minimal_heap.c index 9bcf359..f4adc00 100644 --- a/minimal_heap.c +++ b/minimal_heap.c @@ -3,26 +3,29 @@ #define MIHP_MIN(A, B) (A) < (B) ? (A) : (B) #define MIHP_MAX(A, B) (A) > (B) ? (A) : (B) -MIHP_HeapInfo* MIHP_CreateHeap(size_t initialSize, size_t allocationAlignment) +MIHP_HeapInfo* MIHP_CreateHeap(MIHP_HeapConfig config) { MIHP_HeapInfo* heap = (MIHP_HeapInfo*)MIHP_PlatformRequestMemory(sizeof(MIHP_HeapInfo)); if (heap == NULL) return NULL; - heap->FirstArea = MIHP_CreateHeapMemoryArea(heap, initialSize); + heap->Config = config; + heap->FirstArea = MIHP_CreateHeapMemoryArea(heap, config.MinimalMemoryAreaSize); + heap->FirstArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(heap->FirstArea); + if (heap->FirstArea == NULL) { MIHP_PlatformFreeMemory(heap, sizeof(MIHP_HeapInfo)); return NULL; } - heap->AllocationAlignment = allocationAlignment; return heap; } bool MIHP_DestroyHeap(MIHP_HeapInfo* heap, bool force) { - MIHP_ASSERT(heap); + if (heap == NULL) + return false; if (!force && heap->Stats.NumTotalOccupiedSegments > 0) return false; @@ -31,7 +34,9 @@ bool MIHP_DestroyHeap(MIHP_HeapInfo* heap, bool force) while (nextArea) { MIHP_HeapMemoryAreaHeader* currentArea = nextArea; + MIHP_ValidateHeapMemoryAreaHeader(currentArea); nextArea = currentArea->NextArea; + MIHP_DestroyHeapMemoryArea(heap, currentArea); } @@ -41,7 +46,79 @@ bool MIHP_DestroyHeap(MIHP_HeapInfo* heap, bool force) void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size) { - return NULL; + if (heap == NULL) + return NULL; + + if (size == 0) + return NULL; + + if (size > heap->Config.MaximalMemoryAreaSize) + return NULL; + + MIHP_LOCK_HEAP(&heap->HeapLock); + + MIHP_HeapMemoryAreaHeader* nextArea = heap->FirstArea; + while (nextArea) + { + MIHP_HeapMemoryAreaHeader* currentArea = nextArea; + MIHP_ValidateHeapMemoryAreaHeader(currentArea); + nextArea = currentArea->NextArea; + + if (currentArea->NumOccupiedSegments == currentArea->NumSegments) + continue; + + MIHP_HeapSegmentHeader* nextSegment = currentArea->FirstSegment; + while (nextSegment) + { + MIHP_HeapSegmentHeader* currentSegment = nextSegment; + MIHP_ValidateHeapSegmentHeader(currentSegment); + nextSegment = currentSegment->NextSegment; + + if (currentSegment->OccupiedSize != 0) + continue; + + size_t headerSize = MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapSegmentHeader)); + size_t minimalPayloadSize = heap->Config.AllocationAlignment; + MIHP_HeapSegmentHeader* targetSegment = NULL; + + if (currentSegment->SegmentSize >= 2 * headerSize + size + minimalPayloadSize) + MIHP_SplitHeapSegment(currentSegment, headerSize + size, &targetSegment); + else if (currentSegment->SegmentSize >= headerSize + size) + targetSegment = currentSegment; + else + continue; + + targetSegment->OccupiedSize = size; + targetSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(targetSegment); + + MIHP_UNLOCK_HEAP(&heap->HeapLock); + + void* data = (char*)targetSegment + headerSize; + +#if MIHP_ZERO_OUT_ALLOCATIONS + for (size_t i = 0; i < size; ++i) + *(char*)data = 0; +#endif + + return data; + } + } + + size_t newAreaSize = heap->Stats.TotalSize; + + while (newAreaSize < size) + newAreaSize = MIHP_MIN(heap->Config.MaximalMemoryAreaSize, newAreaSize * 2); + + MIHP_HeapMemoryAreaHeader* newArea = MIHP_CreateHeapMemoryArea(heap, newAreaSize); + newArea->NextArea = heap->FirstArea; + heap->FirstArea->PreviousArea = newArea; + heap->FirstArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(heap->FirstArea); + + heap->FirstArea = newArea; + newArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(newArea); + + MIHP_UNLOCK_HEAP(&heap->HeapLock); + return MIHP_Allocate(heap, size); } void* MIHP_Realloc(MIHP_HeapInfo* heap, void* ptr, size_t newSize) @@ -51,10 +128,18 @@ void* MIHP_Realloc(MIHP_HeapInfo* heap, void* ptr, size_t newSize) void MIHP_Free(MIHP_HeapInfo* heap, void* ptr) { + if (heap == NULL) + return; + + if (ptr == NULL) + return; } bool MIHP_IsPointerInHeap(MIHP_HeapInfo* heap, void* ptr) { + if (heap == NULL) + return false; + MIHP_LOCK_HEAP(&heap->HeapLock); size_t searchingPtr = (size_t)ptr; @@ -94,6 +179,8 @@ MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_HeapInfo* heap, size_t return NULL; heap->Stats.NumMemoryAreas++; + heap->Stats.TotalSize += effectiveSize; + area->NextArea = NULL; area->PreviousArea = NULL; area->AreaSize = effectiveSize; @@ -103,8 +190,7 @@ MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_HeapInfo* heap, size_t size_t headerSize = MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapMemoryAreaHeader)); area->FirstSegment = MIHP_InitializeHeapSegment(area, (char*)area + headerSize, area->AreaSize - headerSize); - - area->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(area); + area->FirstSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(area->FirstSegment); return area; } @@ -116,6 +202,7 @@ bool MIHP_DestroyHeapMemoryArea(MIHP_HeapInfo* heap, MIHP_HeapMemoryAreaHeader* size_t areaNumSegments = memoryArea->NumSegments; size_t areaNumOccupiedSegments = memoryArea->NumOccupiedSegments; + size_t areaSize = memoryArea->AreaSize; if (!MIHP_PlatformFreeMemory(memoryArea, memoryArea->AreaSize)) return false; @@ -123,6 +210,8 @@ bool MIHP_DestroyHeapMemoryArea(MIHP_HeapInfo* heap, MIHP_HeapMemoryAreaHeader* heap->Stats.NumTotalSegments -= areaNumSegments; heap->Stats.NumTotalOccupiedSegments -= areaNumOccupiedSegments; heap->Stats.NumMemoryAreas--; + heap->Stats.TotalSize -= areaSize; + return true; } @@ -138,8 +227,6 @@ MIHP_HeapSegmentHeader* MIHP_InitializeHeapSegment(MIHP_HeapMemoryAreaHeader* ar segment->PreviousSegment = NULL; segment->OwningMemoryArea = area; - segment->Checksum = MIHP_GenerateHeapSegmentChecksum(segment); - area->NumSegments++; area->OwningHeap->Stats.NumTotalSegments++; return segment; @@ -170,8 +257,6 @@ bool MIHP_UninitializeHeapSegment(MIHP_HeapSegmentHeader* segment) bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegmentMinSize, MIHP_HeapSegmentHeader** outNewSegment) { MIHP_ASSERT(sourceSegment); - MIHP_ValidateHeapSegmentHeader(sourceSegment); - MIHP_ValidateHeapMemoryAreaHeader(sourceSegment->OwningMemoryArea); size_t headerSize = MIHP_GetHeapAlignedSize(sourceSegment->OwningMemoryArea->OwningHeap, sizeof(MIHP_HeapSegmentHeader)); size_t effectiveNewSegmentSize = MIHP_GetHeapAlignedSize(sourceSegment->OwningMemoryArea->OwningHeap, newSegmentMinSize); @@ -191,7 +276,11 @@ bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegm newSegment->PreviousSegment = sourceSegment; if (sourceSegment->NextSegment) + { + MIHP_ValidateHeapSegmentHeader(sourceSegment->NextSegment); sourceSegment->NextSegment->PreviousSegment = newSegment; + sourceSegment->NextSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(sourceSegment->NextSegment); + } sourceSegment->NextSegment = newSegment; @@ -210,17 +299,17 @@ bool MIHP_MergeHeapSegments(MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegm MIHP_ASSERT(segmentToAbsorb); MIHP_ASSERT(sourceSegment->NextSegment == segmentToAbsorb); - MIHP_ValidateHeapSegmentHeader(sourceSegment); - MIHP_ValidateHeapSegmentHeader(segmentToAbsorb); - MIHP_ValidateHeapMemoryAreaHeader(segmentToAbsorb->OwningMemoryArea); - if (segmentToAbsorb->OccupiedSize > 0) return false; sourceSegment->NextSegment = segmentToAbsorb->NextSegment; if (sourceSegment->NextSegment) + { + MIHP_ValidateHeapSegmentHeader(sourceSegment->NextSegment); sourceSegment->NextSegment->PreviousSegment = sourceSegment; + sourceSegment->NextSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(sourceSegment->NextSegment); + } sourceSegment->SegmentSize += segmentToAbsorb->SegmentSize; MIHP_UninitializeHeapSegment(segmentToAbsorb); @@ -230,7 +319,7 @@ bool MIHP_MergeHeapSegments(MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegm size_t MIHP_GetHeapAlignedSize(MIHP_HeapInfo* heap, size_t size) { - return (size + (heap->AllocationAlignment - 1)) & ~(heap->AllocationAlignment - 1); + return (size + (heap->Config.AllocationAlignment - 1)) & ~(heap->Config.AllocationAlignment - 1); } uint32_t MIHP_HashMemoryRegion(const void* data, size_t size) diff --git a/minimal_heap.h b/minimal_heap.h index 86c0435..695aa20 100644 --- a/minimal_heap.h +++ b/minimal_heap.h @@ -15,6 +15,14 @@ #define MIHP_HEAP_CORRUPTION_TYPE_FRONT_CANARY_MISMATCH 2 #define MIHP_HEAP_CORRUPTION_TYPE_REAR_CANARY_MISMATCH 3 +typedef struct _MIHP_HeapConfig +{ + size_t AllocationAlignment; + + size_t MinimalMemoryAreaSize; + size_t MaximalMemoryAreaSize; +} MIHP_HeapConfig; + typedef struct _MIHP_HeapStats { size_t NumMemoryAreas; @@ -73,7 +81,7 @@ void MIHP_PlatformOnHeapCorruptionDetected(MIHP_HeapCorruptionInfo info); /* Defines to be configured by the library user */ #define MIHP_MINIMAL_MEMORY_AREA_SIZE (4096 * 32) -#define MIHP_ASSERT(Condition) do { if (Condition) break; *(volatile char*)(0x0) = 0; } while(1) +#define MIHP_ASSERT(Condition) while(1) { if (Condition) break; *(volatile char*)(0x0) = 0; } #define MIHP_HEAP_LOCK_TYPE uint8_t #define MIHP_LOCK_HEAP(LockVariablePtr) {} @@ -82,15 +90,15 @@ void MIHP_PlatformOnHeapCorruptionDetected(MIHP_HeapCorruptionInfo info); typedef struct _MIHP_HeapInfo { + MIHP_HeapConfig Config; MIHP_HeapStats Stats; - size_t AllocationAlignment; MIHP_HeapMemoryAreaHeader* FirstArea; MIHP_HEAP_LOCK_TYPE HeapLock; } MIHP_HeapInfo; /* API Interface */ -MIHP_HeapInfo* MIHP_CreateHeap(size_t initialSize, size_t allocationAlignment); +MIHP_HeapInfo* MIHP_CreateHeap(MIHP_HeapConfig config); bool MIHP_DestroyHeap(MIHP_HeapInfo* heap, bool force); void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size); void* MIHP_Realloc(MIHP_HeapInfo* heap, void* ptr, size_t newSize); From 9b15404de05bda8de2957b6f8443a052dcd68fe6 Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Mon, 8 Jun 2026 04:57:14 +0200 Subject: [PATCH 03/19] free --- minimal_heap.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++---- minimal_heap.h | 2 +- 2 files changed, 92 insertions(+), 9 deletions(-) diff --git a/minimal_heap.c b/minimal_heap.c index f4adc00..6e90b3c 100644 --- a/minimal_heap.c +++ b/minimal_heap.c @@ -77,13 +77,13 @@ void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size) if (currentSegment->OccupiedSize != 0) continue; - size_t headerSize = MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapSegmentHeader)); + size_t segmentHeaderSize = MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapSegmentHeader)); size_t minimalPayloadSize = heap->Config.AllocationAlignment; MIHP_HeapSegmentHeader* targetSegment = NULL; - if (currentSegment->SegmentSize >= 2 * headerSize + size + minimalPayloadSize) - MIHP_SplitHeapSegment(currentSegment, headerSize + size, &targetSegment); - else if (currentSegment->SegmentSize >= headerSize + size) + if (currentSegment->SegmentSize >= 2 * segmentHeaderSize + size + minimalPayloadSize) + MIHP_SplitHeapSegment(currentSegment, segmentHeaderSize + size, &targetSegment); + else if (currentSegment->SegmentSize >= segmentHeaderSize + size) targetSegment = currentSegment; else continue; @@ -91,9 +91,12 @@ void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size) targetSegment->OccupiedSize = size; targetSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(targetSegment); + currentArea->NumOccupiedSegments++; + heap->Stats.NumTotalOccupiedSegments++; + MIHP_UNLOCK_HEAP(&heap->HeapLock); - void* data = (char*)targetSegment + headerSize; + void* data = (char*)targetSegment + segmentHeaderSize; #if MIHP_ZERO_OUT_ALLOCATIONS for (size_t i = 0; i < size; ++i) @@ -110,6 +113,9 @@ void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size) newAreaSize = MIHP_MIN(heap->Config.MaximalMemoryAreaSize, newAreaSize * 2); MIHP_HeapMemoryAreaHeader* newArea = MIHP_CreateHeapMemoryArea(heap, newAreaSize); + if (newArea == NULL) + return NULL; + newArea->NextArea = heap->FirstArea; heap->FirstArea->PreviousArea = newArea; heap->FirstArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(heap->FirstArea); @@ -126,13 +132,75 @@ void* MIHP_Realloc(MIHP_HeapInfo* heap, void* ptr, size_t newSize) return NULL; } -void MIHP_Free(MIHP_HeapInfo* heap, void* ptr) +bool MIHP_Free(MIHP_HeapInfo* heap, void* ptr) { if (heap == NULL) - return; + return false; if (ptr == NULL) - return; + return false; + + if (!MIHP_IsPointerInHeap(heap, ptr)) + return false; + + MIHP_LOCK_HEAP(&heap->HeapLock); + + size_t segmentHeaderSize = MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapSegmentHeader)); + MIHP_HeapSegmentHeader* segment = (char*)ptr - segmentHeaderSize; + MIHP_ValidateHeapSegmentHeader(segment); + + MIHP_HeapMemoryAreaHeader* area = segment->OwningMemoryArea; + MIHP_ValidateHeapMemoryAreaHeader(area); + + segment->OccupiedSize = 0; + area->NumOccupiedSegments--; + heap->Stats.NumTotalOccupiedSegments--; + segment->Checksum = MIHP_GenerateHeapSegmentChecksum(segment); + + if (area->NumOccupiedSegments == 0 && heap->Stats.NumMemoryAreas > 1) + { + MIHP_HeapMemoryAreaHeader* prevArea = area->PreviousArea; + MIHP_HeapMemoryAreaHeader* nextArea = area->NextArea; + + if (MIHP_DestroyHeapMemoryArea(heap, area)) + { + if (prevArea) + { + MIHP_ValidateHeapMemoryAreaHeader(prevArea); + prevArea->NextArea = nextArea; + prevArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(prevArea->NextArea); + } + else + heap->FirstArea = nextArea; + + if (nextArea) + { + MIHP_ValidateHeapMemoryAreaHeader(nextArea); + nextArea->PreviousArea = prevArea; + nextArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(nextArea); + } + + MIHP_UNLOCK_HEAP(&heap->HeapLock); + return true; + } + } + + if (segment->NextSegment) + { + MIHP_ValidateHeapSegmentHeader(segment->NextSegment); + if (segment->NextSegment->OccupiedSize == 0) + MIHP_MergeHeapSegments(segment, segment->NextSegment); + } + + if (segment->PreviousSegment) + { + MIHP_ValidateHeapSegmentHeader(segment->PreviousSegment); + if (segment->PreviousSegment->OccupiedSize == 0) + MIHP_MergeHeapSegments(segment->PreviousSegment, segment); + } + + MIHP_UNLOCK_HEAP(&heap->HeapLock); + return true; } bool MIHP_IsPointerInHeap(MIHP_HeapInfo* heap, void* ptr) @@ -166,6 +234,21 @@ bool MIHP_IsPointerInHeap(MIHP_HeapInfo* heap, void* ptr) void MIHP_ValidateHeap(MIHP_HeapInfo* heap) { + MIHP_HeapMemoryAreaHeader* nextArea = heap->FirstArea; + while (nextArea) + { + MIHP_HeapMemoryAreaHeader* currentArea = nextArea; + MIHP_ValidateHeapMemoryAreaHeader(currentArea); + nextArea = currentArea->NextArea; + + MIHP_HeapSegmentHeader* nextSegment = currentArea->FirstSegment; + while (nextSegment) + { + MIHP_HeapSegmentHeader* currentSegment = nextSegment; + MIHP_ValidateHeapSegmentHeader(currentSegment); + nextSegment = currentSegment->NextSegment; + } + } } MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_HeapInfo* heap, size_t requestedSize) diff --git a/minimal_heap.h b/minimal_heap.h index 695aa20..5406bdc 100644 --- a/minimal_heap.h +++ b/minimal_heap.h @@ -102,7 +102,7 @@ MIHP_HeapInfo* MIHP_CreateHeap(MIHP_HeapConfig config); bool MIHP_DestroyHeap(MIHP_HeapInfo* heap, bool force); void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size); void* MIHP_Realloc(MIHP_HeapInfo* heap, void* ptr, size_t newSize); -void MIHP_Free(MIHP_HeapInfo* heap, void* ptr); +bool MIHP_Free(MIHP_HeapInfo* heap, void* ptr); bool MIHP_IsPointerInHeap(MIHP_HeapInfo* heap, void* ptr); void MIHP_ValidateHeap(MIHP_HeapInfo* heap); From 4cabd7bf291399f1e8428520c2113e826711834b Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Mon, 8 Jun 2026 04:58:45 +0200 Subject: [PATCH 04/19] Update .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index c6127b3..5de59ff 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,6 @@ modules.order Module.symvers Mkfile.old dkms.conf + +# Visual Studio +.vs/ \ No newline at end of file From 0da008fec7637fc7a6140921a61f8859cb066102 Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Mon, 8 Jun 2026 06:23:55 +0200 Subject: [PATCH 05/19] it works --- minimal_heap.c | 103 +++++++++++++++++++++++--------------------- minimal_heap.h | 20 ++++----- minimal_heap_test.c | 65 ++++++++++++++++++++++++---- 3 files changed, 121 insertions(+), 67 deletions(-) diff --git a/minimal_heap.c b/minimal_heap.c index 6e90b3c..d0c98a5 100644 --- a/minimal_heap.c +++ b/minimal_heap.c @@ -3,22 +3,27 @@ #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; + MIHP_HeapInfo* MIHP_CreateHeap(MIHP_HeapConfig config) { MIHP_HeapInfo* heap = (MIHP_HeapInfo*)MIHP_PlatformRequestMemory(sizeof(MIHP_HeapInfo)); if (heap == NULL) return NULL; - heap->Config = config; - heap->FirstArea = MIHP_CreateHeapMemoryArea(heap, config.MinimalMemoryAreaSize); - heap->FirstArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(heap->FirstArea); + MIHP_MEMSET(heap, sizeof(MIHP_HeapInfo), 0); + heap->Config = config; + + heap->FirstArea = MIHP_CreateHeapMemoryArea(heap, config.MinimalMemoryAreaSize); if (heap->FirstArea == NULL) { MIHP_PlatformFreeMemory(heap, sizeof(MIHP_HeapInfo)); return NULL; } + heap->FirstArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(heap->FirstArea); + return heap; } @@ -34,7 +39,7 @@ bool MIHP_DestroyHeap(MIHP_HeapInfo* heap, bool force) while (nextArea) { MIHP_HeapMemoryAreaHeader* currentArea = nextArea; - MIHP_ValidateHeapMemoryAreaHeader(currentArea); + MIHP_ValidateHeapMemoryAreaHeader(heap, currentArea); nextArea = currentArea->NextArea; MIHP_DestroyHeapMemoryArea(heap, currentArea); @@ -61,7 +66,7 @@ void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size) while (nextArea) { MIHP_HeapMemoryAreaHeader* currentArea = nextArea; - MIHP_ValidateHeapMemoryAreaHeader(currentArea); + MIHP_ValidateHeapMemoryAreaHeader(heap, currentArea); nextArea = currentArea->NextArea; if (currentArea->NumOccupiedSegments == currentArea->NumSegments) @@ -71,7 +76,7 @@ void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size) while (nextSegment) { MIHP_HeapSegmentHeader* currentSegment = nextSegment; - MIHP_ValidateHeapSegmentHeader(currentSegment); + MIHP_ValidateHeapSegmentHeader(heap, currentSegment); nextSegment = currentSegment->NextSegment; if (currentSegment->OccupiedSize != 0) @@ -92,16 +97,14 @@ void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size) targetSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(targetSegment); currentArea->NumOccupiedSegments++; + currentArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(currentArea); + heap->Stats.NumTotalOccupiedSegments++; MIHP_UNLOCK_HEAP(&heap->HeapLock); void* data = (char*)targetSegment + segmentHeaderSize; - -#if MIHP_ZERO_OUT_ALLOCATIONS - for (size_t i = 0; i < size; ++i) - *(char*)data = 0; -#endif + MIHP_MEMSET(data, size, heap->Config.AllocationInitialValue); return data; } @@ -146,16 +149,19 @@ bool MIHP_Free(MIHP_HeapInfo* heap, void* ptr) MIHP_LOCK_HEAP(&heap->HeapLock); size_t segmentHeaderSize = MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapSegmentHeader)); - MIHP_HeapSegmentHeader* segment = (char*)ptr - segmentHeaderSize; - MIHP_ValidateHeapSegmentHeader(segment); + MIHP_HeapSegmentHeader* segment = (MIHP_HeapSegmentHeader*)((char*)ptr - segmentHeaderSize); + MIHP_ValidateHeapSegmentHeader(heap, segment); MIHP_HeapMemoryAreaHeader* area = segment->OwningMemoryArea; - MIHP_ValidateHeapMemoryAreaHeader(area); + MIHP_ValidateHeapMemoryAreaHeader(heap, area); segment->OccupiedSize = 0; - area->NumOccupiedSegments--; - heap->Stats.NumTotalOccupiedSegments--; segment->Checksum = MIHP_GenerateHeapSegmentChecksum(segment); + + area->NumOccupiedSegments--; + area->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(area); + + heap->Stats.NumTotalOccupiedSegments--; if (area->NumOccupiedSegments == 0 && heap->Stats.NumMemoryAreas > 1) { @@ -166,16 +172,16 @@ bool MIHP_Free(MIHP_HeapInfo* heap, void* ptr) { if (prevArea) { - MIHP_ValidateHeapMemoryAreaHeader(prevArea); + MIHP_ValidateHeapMemoryAreaHeader(heap, prevArea); prevArea->NextArea = nextArea; - prevArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(prevArea->NextArea); + prevArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(prevArea); } else heap->FirstArea = nextArea; if (nextArea) { - MIHP_ValidateHeapMemoryAreaHeader(nextArea); + MIHP_ValidateHeapMemoryAreaHeader(heap, nextArea); nextArea->PreviousArea = prevArea; nextArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(nextArea); } @@ -187,14 +193,14 @@ bool MIHP_Free(MIHP_HeapInfo* heap, void* ptr) if (segment->NextSegment) { - MIHP_ValidateHeapSegmentHeader(segment->NextSegment); + MIHP_ValidateHeapSegmentHeader(heap, segment->NextSegment); if (segment->NextSegment->OccupiedSize == 0) MIHP_MergeHeapSegments(segment, segment->NextSegment); } if (segment->PreviousSegment) { - MIHP_ValidateHeapSegmentHeader(segment->PreviousSegment); + MIHP_ValidateHeapSegmentHeader(heap, segment->PreviousSegment); if (segment->PreviousSegment->OccupiedSize == 0) MIHP_MergeHeapSegments(segment->PreviousSegment, segment); } @@ -238,14 +244,14 @@ void MIHP_ValidateHeap(MIHP_HeapInfo* heap) while (nextArea) { MIHP_HeapMemoryAreaHeader* currentArea = nextArea; - MIHP_ValidateHeapMemoryAreaHeader(currentArea); + MIHP_ValidateHeapMemoryAreaHeader(heap, currentArea); nextArea = currentArea->NextArea; MIHP_HeapSegmentHeader* nextSegment = currentArea->FirstSegment; while (nextSegment) { MIHP_HeapSegmentHeader* currentSegment = nextSegment; - MIHP_ValidateHeapSegmentHeader(currentSegment); + MIHP_ValidateHeapSegmentHeader(heap, currentSegment); nextSegment = currentSegment->NextSegment; } } @@ -261,20 +267,19 @@ MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_HeapInfo* heap, size_t if (area == NULL) return NULL; - heap->Stats.NumMemoryAreas++; - heap->Stats.TotalSize += effectiveSize; + MIHP_MEMSET(area, sizeof(MIHP_HeapMemoryAreaHeader), 0); - area->NextArea = NULL; - area->PreviousArea = NULL; area->AreaSize = effectiveSize; - area->NumOccupiedSegments = 0; - area->NumSegments = 0; 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->Checksum = MIHP_GenerateHeapSegmentChecksum(area->FirstSegment); + heap->Stats.NumMemoryAreas++; + heap->Stats.TotalSize += effectiveSize; + return area; } @@ -304,14 +309,16 @@ MIHP_HeapSegmentHeader* MIHP_InitializeHeapSegment(MIHP_HeapMemoryAreaHeader* ar MIHP_ASSERT(segmentStart); MIHP_HeapSegmentHeader* segment = (MIHP_HeapSegmentHeader*)segmentStart; + + MIHP_MEMSET(segment, sizeof(MIHP_HeapSegmentHeader), 0); + segment->SegmentSize = segmentSize; - segment->OccupiedSize = 0; - segment->NextSegment = NULL; - segment->PreviousSegment = NULL; segment->OwningMemoryArea = area; + segment->Checksum = ~0; area->NumSegments++; area->OwningHeap->Stats.NumTotalSegments++; + return segment; } @@ -323,16 +330,10 @@ bool MIHP_UninitializeHeapSegment(MIHP_HeapSegmentHeader* segment) return false; segment->OwningMemoryArea->NumSegments--; + segment->OwningMemoryArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(segment->OwningMemoryArea); segment->OwningMemoryArea->OwningHeap->Stats.NumTotalSegments--; -#if MIHP_ZERO_OUT_MERGED_HEADERS - segment->SegmentSize = 0; - segment->OccupiedSize = 0; - segment->NextSegment = NULL; - segment->PreviousSegment = NULL; - segment->OwningMemoryArea = NULL; - segment->Checksum = 0; -#endif + MIHP_MEMSET(segment, sizeof(MIHP_HeapSegmentHeader), 0); return true; } @@ -360,7 +361,7 @@ bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegm if (sourceSegment->NextSegment) { - MIHP_ValidateHeapSegmentHeader(sourceSegment->NextSegment); + MIHP_ValidateHeapSegmentHeader(sourceSegment->OwningMemoryArea->OwningHeap, sourceSegment->NextSegment); sourceSegment->NextSegment->PreviousSegment = newSegment; sourceSegment->NextSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(sourceSegment->NextSegment); } @@ -389,7 +390,7 @@ bool MIHP_MergeHeapSegments(MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegm if (sourceSegment->NextSegment) { - MIHP_ValidateHeapSegmentHeader(sourceSegment->NextSegment); + MIHP_ValidateHeapSegmentHeader(sourceSegment->OwningMemoryArea->OwningHeap, sourceSegment->NextSegment); sourceSegment->NextSegment->PreviousSegment = sourceSegment; sourceSegment->NextSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(sourceSegment->NextSegment); } @@ -397,10 +398,12 @@ bool MIHP_MergeHeapSegments(MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegm sourceSegment->SegmentSize += segmentToAbsorb->SegmentSize; MIHP_UninitializeHeapSegment(segmentToAbsorb); + sourceSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(sourceSegment); + return true; } -size_t MIHP_GetHeapAlignedSize(MIHP_HeapInfo* heap, size_t size) +size_t MIHP_GetHeapAlignedSize(const MIHP_HeapInfo* heap, size_t size) { return (size + (heap->Config.AllocationAlignment - 1)) & ~(heap->Config.AllocationAlignment - 1); } @@ -427,7 +430,7 @@ uint32_t MIHP_GenerateHeapMemoryAreaChecksum(const MIHP_HeapMemoryAreaHeader* ar MIHP_ASSERT(area); // Do not include the checksum itself into the new checksum - size_t size = sizeof(MIHP_HeapMemoryAreaHeader) - sizeof(area->Checksum); + size_t size = offsetof(MIHP_HeapMemoryAreaHeader, Checksum); return MIHP_HashMemoryRegion(area, size); } @@ -440,21 +443,22 @@ uint32_t MIHP_GenerateHeapSegmentChecksum(const MIHP_HeapSegmentHeader* segment) MIHP_ASSERT(segment); // Do not include the checksum itself into the new checksum - size_t size = sizeof(MIHP_HeapSegmentHeader) - sizeof(segment->Checksum); + size_t size = offsetof(MIHP_HeapSegmentHeader, Checksum); return MIHP_HashMemoryRegion(segment, size); } -void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_HeapMemoryAreaHeader* area) +void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_HeapInfo* heap, const MIHP_HeapMemoryAreaHeader* area) { #if !MIHP_USE_HEAP_STRUCTURE_CHECKSUM_VALIDATION return; #endif - size_t newChecksum = MIHP_GenerateHeapMemoryAreaChecksum(area); + uint32_t newChecksum = MIHP_GenerateHeapMemoryAreaChecksum(area); if (area->Checksum != newChecksum) { MIHP_HeapCorruptionInfo corruptionInfo; + corruptionInfo.Heap = heap; corruptionInfo.Type = MIHP_HEAP_CORRUPTION_TYPE_MEMORY_AREA_CHECKSUM_MISMATCH; corruptionInfo.Ptr = area; corruptionInfo.ExpectedValue = area->Checksum; @@ -464,17 +468,18 @@ void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_HeapMemoryAreaHeader* area) } } -void MIHP_ValidateHeapSegmentHeader(const MIHP_HeapSegmentHeader* segment) +void MIHP_ValidateHeapSegmentHeader(const MIHP_HeapInfo* heap, const MIHP_HeapSegmentHeader* segment) { #if !MIHP_USE_HEAP_STRUCTURE_CHECKSUM_VALIDATION return; #endif - size_t newChecksum = MIHP_GenerateHeapSegmentChecksum(segment); + uint32_t newChecksum = MIHP_GenerateHeapSegmentChecksum(segment); if (segment->Checksum != newChecksum) { MIHP_HeapCorruptionInfo corruptionInfo; + corruptionInfo.Heap = heap; corruptionInfo.Type = MIHP_HEAP_CORRUPTION_TYPE_SEGMENT_CHECKSUM_MISMATCH; corruptionInfo.Ptr = segment; corruptionInfo.ExpectedValue = segment->Checksum; diff --git a/minimal_heap.h b/minimal_heap.h index 5406bdc..740be33 100644 --- a/minimal_heap.h +++ b/minimal_heap.h @@ -7,9 +7,6 @@ #define MIHP_USE_HEAP_STRUCTURE_CHECKSUM_VALIDATION 1 #define MIHP_USE_CANARY_VALIDATION 1 -#define MIHP_ZERO_OUT_MERGED_HEADERS 1 -#define MIHP_ZERO_OUT_ALLOCATIONS 1 - #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 @@ -21,6 +18,8 @@ typedef struct _MIHP_HeapConfig size_t MinimalMemoryAreaSize; size_t MaximalMemoryAreaSize; + + char AllocationInitialValue; } MIHP_HeapConfig; typedef struct _MIHP_HeapStats @@ -66,10 +65,11 @@ typedef struct _MIHP_HeapSegmentHeader typedef struct _MIHP_HeapCorruptionInfo { - uint8_t Type; - const void* Ptr; - uint32_t ExpectedValue; - uint32_t ActualValue; + const struct _MIHP_HeapInfo* Heap; + uint8_t Type; + const void* Ptr; + uint32_t ExpectedValue; + uint32_t ActualValue; } MIHP_HeapCorruptionInfo; /* Hooks to be implemented by the library user */ @@ -118,12 +118,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); -size_t MIHP_GetHeapAlignedSize(MIHP_HeapInfo* heap, size_t size); +size_t MIHP_GetHeapAlignedSize(const MIHP_HeapInfo* heap, size_t size); uint32_t MIHP_HashMemoryRegion(const void* data, size_t size); uint32_t MIHP_GenerateHeapMemoryAreaChecksum(const MIHP_HeapMemoryAreaHeader* area); uint32_t MIHP_GenerateHeapSegmentChecksum(const MIHP_HeapSegmentHeader* segment); -void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_HeapMemoryAreaHeader* area); -void MIHP_ValidateHeapSegmentHeader(const MIHP_HeapSegmentHeader* segment); +void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_HeapInfo* heap, const MIHP_HeapMemoryAreaHeader* area); +void MIHP_ValidateHeapSegmentHeader(const MIHP_HeapInfo* heap, const MIHP_HeapSegmentHeader* segment); /* */ diff --git a/minimal_heap_test.c b/minimal_heap_test.c index 4e76e6e..146d506 100644 --- a/minimal_heap_test.c +++ b/minimal_heap_test.c @@ -1,26 +1,75 @@ #include "minimal_heap.h" +#include +#include +#include void* MIHP_PlatformRequestMemory(size_t size) { - + return malloc(size); } bool MIHP_PlatformFreeMemory(void* ptr, size_t size) { - -} - -uint8_t MIHP_PlatformGetMinimalMemoryAlignment() -{ - + free(ptr); + return true; } void MIHP_PlatformOnHeapCorruptionDetected(MIHP_HeapCorruptionInfo info) { - + __debugbreak(); } +#define NUM_ALLOCATIONS (4096 * 1) + +void* myptrs[NUM_ALLOCATIONS] = { 0 }; + int main() { + MIHP_HeapConfig config = {0}; + config.AllocationAlignment = 128; + config.MinimalMemoryAreaSize = 4096 * 32; + config.MaximalMemoryAreaSize = 4096 * 4096; + MIHP_HeapInfo* myHeap = MIHP_CreateHeap(config); + + { + clock_t start = clock(); + + for (int i = 0; i < NUM_ALLOCATIONS; i++) + { + size_t size = 473 + (i % 5 == 0 ? 854 : 0); + //myptrs[i] = malloc(size); + myptrs[i] = MIHP_Allocate(myHeap, size); + MIHP_ValidateHeap(myHeap); + } + + clock_t end = clock(); + printf("Allocating took %f seconds\n", ((double)(end - start)) / CLOCKS_PER_SEC); + } + + + __debugbreak(); + + { + clock_t start = clock(); + + for (int z = 15; z >= 0; z--) + { + for (int y = 0; y < NUM_ALLOCATIONS / 16; y++) + { + int i = z + y * 16; + + //free(myptrs[i]); + MIHP_Free(myHeap, myptrs[i]); + MIHP_ValidateHeap(myHeap); + myptrs[i] = NULL; + } + } + + clock_t end = clock(); + printf("Freeing took %f seconds\n", ((double)(end - start)) / CLOCKS_PER_SEC); + } + + + __debugbreak(); } From b50b2548ababbd7854283851566120a571f5f2ba Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Mon, 8 Jun 2026 07:24:17 +0200 Subject: [PATCH 06/19] more tests --- minimal_heap.c | 22 ++++++++++++ minimal_heap.h | 5 +-- minimal_heap_test.c | 87 +++++++++++++++++++++++++++++---------------- 3 files changed, 82 insertions(+), 32 deletions(-) diff --git a/minimal_heap.c b/minimal_heap.c index d0c98a5..fa40da2 100644 --- a/minimal_heap.c +++ b/minimal_heap.c @@ -5,8 +5,16 @@ #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) + MIHP_HeapInfo* MIHP_CreateHeap(MIHP_HeapConfig config) { + if (config.AllocationAlignment < sizeof(size_t)) + return NULL; + + if (!MIHP_IS_PO2(config.AllocationAlignment)) + return NULL; + MIHP_HeapInfo* heap = (MIHP_HeapInfo*)MIHP_PlatformRequestMemory(sizeof(MIHP_HeapInfo)); if (heap == NULL) return NULL; @@ -238,6 +246,20 @@ bool MIHP_IsPointerInHeap(MIHP_HeapInfo* heap, void* ptr) return false; } +size_t MIHP_GetPtrAllocationSize(MIHP_HeapInfo* heap, void* ptr) +{ + if (!MIHP_IsPointerInHeap(heap, ptr)) + return 0; + + MIHP_LOCK_HEAP(&heap->HeapLock); + + size_t segmentHeaderSize = MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapSegmentHeader)); + MIHP_HeapSegmentHeader* segment = (MIHP_HeapSegmentHeader*)((char*)ptr - segmentHeaderSize); + MIHP_ValidateHeapSegmentHeader(heap, segment); + + return segment->OccupiedSize; +} + void MIHP_ValidateHeap(MIHP_HeapInfo* heap) { MIHP_HeapMemoryAreaHeader* nextArea = heap->FirstArea; diff --git a/minimal_heap.h b/minimal_heap.h index 740be33..c21e8e0 100644 --- a/minimal_heap.h +++ b/minimal_heap.h @@ -4,7 +4,7 @@ #include #include -#define MIHP_USE_HEAP_STRUCTURE_CHECKSUM_VALIDATION 1 +#define MIHP_USE_HEAP_STRUCTURE_CHECKSUM_VALIDATION 0 #define MIHP_USE_CANARY_VALIDATION 1 #define MIHP_HEAP_CORRUPTION_TYPE_MEMORY_AREA_CHECKSUM_MISMATCH 0 @@ -38,7 +38,7 @@ typedef struct _MIHP_HeapMemoryAreaHeader size_t NumOccupiedSegments; struct _MIHP_HeapMemoryAreaHeader* NextArea; - struct _MIHP_HeapMemoryAreaHeader* PreviousArea; + //struct _MIHP_HeapMemoryAreaHeader* PreviousArea; struct _MIHP_HeapInfo* OwningHeap; struct _MIHP_HeapSegmentHeader* FirstSegment; @@ -105,6 +105,7 @@ void* MIHP_Realloc(MIHP_HeapInfo* heap, void* ptr, size_t newSize); bool MIHP_Free(MIHP_HeapInfo* heap, void* ptr); bool MIHP_IsPointerInHeap(MIHP_HeapInfo* heap, void* ptr); +size_t MIHP_GetPtrAllocationSize(MIHP_HeapInfo* heap, void* ptr); void MIHP_ValidateHeap(MIHP_HeapInfo* heap); /* */ diff --git a/minimal_heap_test.c b/minimal_heap_test.c index 146d506..151f29e 100644 --- a/minimal_heap_test.c +++ b/minimal_heap_test.c @@ -3,6 +3,8 @@ #include #include +#define USE_MALLOC 0 + void* MIHP_PlatformRequestMemory(size_t size) { return malloc(size); @@ -19,56 +21,81 @@ void MIHP_PlatformOnHeapCorruptionDetected(MIHP_HeapCorruptionInfo info) __debugbreak(); } -#define NUM_ALLOCATIONS (4096 * 1) +#define NUM_ALLOCATIONS (4096 * 512) void* myptrs[NUM_ALLOCATIONS] = { 0 }; int main() { MIHP_HeapConfig config = {0}; - config.AllocationAlignment = 128; + config.AllocationInitialValue = 0xbe; + config.AllocationAlignment = 16; config.MinimalMemoryAreaSize = 4096 * 32; - config.MaximalMemoryAreaSize = 4096 * 4096; + config.MaximalMemoryAreaSize = 4096ull * 4096ull * 4096ull; MIHP_HeapInfo* myHeap = MIHP_CreateHeap(config); + for (int i = 0; i < NUM_ALLOCATIONS; i++) { - clock_t start = clock(); - - for (int i = 0; i < NUM_ALLOCATIONS; i++) - { - size_t size = 473 + (i % 5 == 0 ? 854 : 0); - //myptrs[i] = malloc(size); - myptrs[i] = MIHP_Allocate(myHeap, size); - MIHP_ValidateHeap(myHeap); - } - - clock_t end = clock(); - printf("Allocating took %f seconds\n", ((double)(end - start)) / CLOCKS_PER_SEC); + size_t size = 473 + (i % 5 == 0 ? 854 : 0); +#if USE_MALLOC + myptrs[i] = malloc(size); +#else + myptrs[i] = MIHP_Allocate(myHeap, size); + MIHP_ValidateHeap(myHeap); +#endif } - __debugbreak(); + for (int i = 0; i < NUM_ALLOCATIONS; i++) { - clock_t start = clock(); - - for (int z = 15; z >= 0; z--) + if (rand() % 3 == 0) { - for (int y = 0; y < NUM_ALLOCATIONS / 16; y++) - { - int i = z + y * 16; +#if USE_MALLOC + free(myptrs[i]); +#else + MIHP_Free(myHeap, myptrs[i]); + MIHP_ValidateHeap(myHeap); +#endif - //free(myptrs[i]); - MIHP_Free(myHeap, myptrs[i]); - MIHP_ValidateHeap(myHeap); - myptrs[i] = NULL; - } + myptrs[i] = NULL; } - - clock_t end = clock(); - printf("Freeing took %f seconds\n", ((double)(end - start)) / CLOCKS_PER_SEC); } + __debugbreak(); + + for (int i = 0; i < NUM_ALLOCATIONS; i++) + { + volatile int n = i; + if (!myptrs[i]) + { + size_t size = 541 + rand() % 2564; + +#if USE_MALLOC + myptrs[i] = malloc(size); +#else + myptrs[i] = MIHP_Allocate(myHeap, size); + MIHP_ValidateHeap(myHeap); +#endif + } + } + + __debugbreak(); + + for (int z = 15; z >= 0; z--) + for (int y = 0; y < NUM_ALLOCATIONS / 16; y++) + { + int i = z + y * 16; +#if USE_MALLOC + free(myptrs[i]); +#else + MIHP_Free(myHeap, myptrs[i]); + MIHP_ValidateHeap(myHeap); +#endif + + myptrs[i] = NULL; + } + __debugbreak(); } From 5a84b57b25578973faf087982fd20c96d63fbb5f Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Mon, 8 Jun 2026 07:24:27 +0200 Subject: [PATCH 07/19] Update minimal_heap.h --- minimal_heap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/minimal_heap.h b/minimal_heap.h index c21e8e0..b722674 100644 --- a/minimal_heap.h +++ b/minimal_heap.h @@ -38,7 +38,7 @@ typedef struct _MIHP_HeapMemoryAreaHeader size_t NumOccupiedSegments; struct _MIHP_HeapMemoryAreaHeader* NextArea; - //struct _MIHP_HeapMemoryAreaHeader* PreviousArea; + struct _MIHP_HeapMemoryAreaHeader* PreviousArea; struct _MIHP_HeapInfo* OwningHeap; struct _MIHP_HeapSegmentHeader* FirstSegment; From c134adc3b15577628543ca44b500d8dc041fb830 Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Mon, 8 Jun 2026 07:47:44 +0200 Subject: [PATCH 08/19] performance speedup --- minimal_heap.c | 22 ++++++++++++++++++++-- minimal_heap.h | 4 +++- minimal_heap_test.c | 4 ++-- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/minimal_heap.c b/minimal_heap.c index fa40da2..c80dff9 100644 --- a/minimal_heap.c +++ b/minimal_heap.c @@ -24,6 +24,7 @@ MIHP_HeapInfo* MIHP_CreateHeap(MIHP_HeapConfig config) heap->Config = config; heap->FirstArea = MIHP_CreateHeapMemoryArea(heap, config.MinimalMemoryAreaSize); + heap->LastAllocationArea = heap->FirstArea; if (heap->FirstArea == NULL) { MIHP_PlatformFreeMemory(heap, sizeof(MIHP_HeapInfo)); @@ -70,12 +71,24 @@ void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size) MIHP_LOCK_HEAP(&heap->HeapLock); + bool checkedLastAllocationArea = false; MIHP_HeapMemoryAreaHeader* nextArea = heap->FirstArea; while (nextArea) { - MIHP_HeapMemoryAreaHeader* currentArea = nextArea; + MIHP_HeapMemoryAreaHeader* currentArea = NULL; + + if (!checkedLastAllocationArea) + { + currentArea = heap->LastAllocationArea; + checkedLastAllocationArea = true; + } + else + { + currentArea = nextArea; + nextArea = currentArea->NextArea; + } + MIHP_ValidateHeapMemoryAreaHeader(heap, currentArea); - nextArea = currentArea->NextArea; if (currentArea->NumOccupiedSegments == currentArea->NumSegments) continue; @@ -108,6 +121,8 @@ void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size) currentArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(currentArea); heap->Stats.NumTotalOccupiedSegments++; + heap->Stats.TotalOccupiedSize += targetSegment->OccupiedSize; + heap->LastAllocationArea = currentArea; MIHP_UNLOCK_HEAP(&heap->HeapLock); @@ -163,6 +178,8 @@ bool MIHP_Free(MIHP_HeapInfo* heap, void* ptr) MIHP_HeapMemoryAreaHeader* area = segment->OwningMemoryArea; MIHP_ValidateHeapMemoryAreaHeader(heap, area); + size_t occupiedSize = segment->OccupiedSize; + segment->OccupiedSize = 0; segment->Checksum = MIHP_GenerateHeapSegmentChecksum(segment); @@ -170,6 +187,7 @@ bool MIHP_Free(MIHP_HeapInfo* heap, void* ptr) area->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(area); heap->Stats.NumTotalOccupiedSegments--; + heap->Stats.TotalOccupiedSize -= occupiedSize; if (area->NumOccupiedSegments == 0 && heap->Stats.NumMemoryAreas > 1) { diff --git a/minimal_heap.h b/minimal_heap.h index b722674..dee7193 100644 --- a/minimal_heap.h +++ b/minimal_heap.h @@ -28,6 +28,7 @@ typedef struct _MIHP_HeapStats size_t NumTotalSegments; size_t NumTotalOccupiedSegments; size_t TotalSize; + size_t TotalOccupiedSize; } MIHP_HeapStats; // This structs size must be multiple of 8 @@ -73,7 +74,7 @@ typedef struct _MIHP_HeapCorruptionInfo } MIHP_HeapCorruptionInfo; /* Hooks to be implemented by the library user */ -void* MIHP_PlatformRequestMemory(size_t size); // Alignment must at least be alingment of size_t +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_PlatformOnHeapCorruptionDetected(MIHP_HeapCorruptionInfo info); /* === */ @@ -93,6 +94,7 @@ typedef struct _MIHP_HeapInfo MIHP_HeapConfig Config; MIHP_HeapStats Stats; MIHP_HeapMemoryAreaHeader* FirstArea; + MIHP_HeapMemoryAreaHeader* LastSuccessfulAllocationArea; MIHP_HEAP_LOCK_TYPE HeapLock; } MIHP_HeapInfo; diff --git a/minimal_heap_test.c b/minimal_heap_test.c index 151f29e..52d76aa 100644 --- a/minimal_heap_test.c +++ b/minimal_heap_test.c @@ -21,7 +21,7 @@ void MIHP_PlatformOnHeapCorruptionDetected(MIHP_HeapCorruptionInfo info) __debugbreak(); } -#define NUM_ALLOCATIONS (4096 * 512) +#define NUM_ALLOCATIONS (4096 * 128) void* myptrs[NUM_ALLOCATIONS] = { 0 }; @@ -31,7 +31,7 @@ int main() config.AllocationInitialValue = 0xbe; config.AllocationAlignment = 16; config.MinimalMemoryAreaSize = 4096 * 32; - config.MaximalMemoryAreaSize = 4096ull * 4096ull * 4096ull; + config.MaximalMemoryAreaSize = 4096ull * 4096ull; MIHP_HeapInfo* myHeap = MIHP_CreateHeap(config); for (int i = 0; i < NUM_ALLOCATIONS; i++) From 5da9598053fc61cadda82b7c02d200b16d9fc18f Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Mon, 8 Jun 2026 08:07:09 +0200 Subject: [PATCH 09/19] renaming --- minimal_heap.c | 13 +++++++------ minimal_heap_test.c | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/minimal_heap.c b/minimal_heap.c index c80dff9..16f21c9 100644 --- a/minimal_heap.c +++ b/minimal_heap.c @@ -24,7 +24,7 @@ MIHP_HeapInfo* MIHP_CreateHeap(MIHP_HeapConfig config) heap->Config = config; heap->FirstArea = MIHP_CreateHeapMemoryArea(heap, config.MinimalMemoryAreaSize); - heap->LastAllocationArea = heap->FirstArea; + heap->LastSuccessfulAllocationArea = heap->FirstArea; if (heap->FirstArea == NULL) { MIHP_PlatformFreeMemory(heap, sizeof(MIHP_HeapInfo)); @@ -71,16 +71,16 @@ void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size) MIHP_LOCK_HEAP(&heap->HeapLock); - bool checkedLastAllocationArea = false; + bool triedLastAllocationArea = false; MIHP_HeapMemoryAreaHeader* nextArea = heap->FirstArea; while (nextArea) { MIHP_HeapMemoryAreaHeader* currentArea = NULL; - if (!checkedLastAllocationArea) + if (!triedLastAllocationArea) { - currentArea = heap->LastAllocationArea; - checkedLastAllocationArea = true; + currentArea = heap->LastSuccessfulAllocationArea; + triedLastAllocationArea = true; } else { @@ -122,7 +122,7 @@ void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size) heap->Stats.NumTotalOccupiedSegments++; heap->Stats.TotalOccupiedSize += targetSegment->OccupiedSize; - heap->LastAllocationArea = currentArea; + heap->LastSuccessfulAllocationArea = currentArea; MIHP_UNLOCK_HEAP(&heap->HeapLock); @@ -147,6 +147,7 @@ void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size) heap->FirstArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(heap->FirstArea); heap->FirstArea = newArea; + heap->LastSuccessfulAllocationArea = newArea; newArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(newArea); MIHP_UNLOCK_HEAP(&heap->HeapLock); diff --git a/minimal_heap_test.c b/minimal_heap_test.c index 52d76aa..1d798a4 100644 --- a/minimal_heap_test.c +++ b/minimal_heap_test.c @@ -31,7 +31,7 @@ int main() config.AllocationInitialValue = 0xbe; config.AllocationAlignment = 16; config.MinimalMemoryAreaSize = 4096 * 32; - config.MaximalMemoryAreaSize = 4096ull * 4096ull; + config.MaximalMemoryAreaSize = 4096ull * 4096ull * 4096ull; MIHP_HeapInfo* myHeap = MIHP_CreateHeap(config); for (int i = 0; i < NUM_ALLOCATIONS; i++) From 36da9672d7a9bdd84ecb6ddadfe4924f2b9b9e51 Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Mon, 8 Jun 2026 08:11:52 +0200 Subject: [PATCH 10/19] hgj --- minimal_heap.h | 2 +- minimal_heap_test.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/minimal_heap.h b/minimal_heap.h index dee7193..d5b8bd9 100644 --- a/minimal_heap.h +++ b/minimal_heap.h @@ -4,7 +4,7 @@ #include #include -#define MIHP_USE_HEAP_STRUCTURE_CHECKSUM_VALIDATION 0 +#define MIHP_USE_HEAP_STRUCTURE_CHECKSUM_VALIDATION 1 #define MIHP_USE_CANARY_VALIDATION 1 #define MIHP_HEAP_CORRUPTION_TYPE_MEMORY_AREA_CHECKSUM_MISMATCH 0 diff --git a/minimal_heap_test.c b/minimal_heap_test.c index 1d798a4..fb0c76b 100644 --- a/minimal_heap_test.c +++ b/minimal_heap_test.c @@ -21,7 +21,7 @@ void MIHP_PlatformOnHeapCorruptionDetected(MIHP_HeapCorruptionInfo info) __debugbreak(); } -#define NUM_ALLOCATIONS (4096 * 128) +#define NUM_ALLOCATIONS (4096 * 32) void* myptrs[NUM_ALLOCATIONS] = { 0 }; From 32460dfc094f1469d3313dc61189bc3e0d02b7c9 Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Mon, 8 Jun 2026 09:28:33 +0200 Subject: [PATCH 11/19] realloc and different heap validation types --- minimal_heap.c | 128 ++++++++++++++++++++++++++++++++++++++------ minimal_heap.h | 15 +++--- minimal_heap_test.c | 12 +++-- 3 files changed, 128 insertions(+), 27 deletions(-) diff --git a/minimal_heap.c b/minimal_heap.c index 16f21c9..ca5deec 100644 --- a/minimal_heap.c +++ b/minimal_heap.c @@ -156,7 +156,77 @@ void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size) void* MIHP_Realloc(MIHP_HeapInfo* heap, void* ptr, size_t newSize) { - return NULL; + if (newSize == 0) + { + MIHP_Free(heap, ptr); + return NULL; + } + + if (heap == NULL) + return NULL; + + if (ptr == NULL) + return MIHP_Allocate(heap, newSize); + + if (!MIHP_IsPointerInHeap(heap, ptr)) + return NULL; + + MIHP_LOCK_HEAP(&heap->HeapLock); + + size_t segmentHeaderSize = MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapSegmentHeader)); + MIHP_HeapSegmentHeader* segment = (MIHP_HeapSegmentHeader*)((char*)ptr - segmentHeaderSize); + MIHP_ValidateHeapSegmentHeader(heap, segment); + + if (newSize > segment->OccupiedSize) + { + size_t maxPayloadSize = segment->SegmentSize - segmentHeaderSize; + if (newSize <= maxPayloadSize) + { + MIHP_MEMSET((char*)ptr + segment->OccupiedSize, newSize - segment->OccupiedSize, heap->Config.AllocationInitialValue); + segment->OccupiedSize = newSize; + segment->Checksum = MIHP_GenerateHeapSegmentChecksum(segment); + + MIHP_UNLOCK_HEAP(&heap->HeapLock); + return ptr; + } + + if (segment->NextSegment && MIHP_MergeHeapSegments(segment, segment->NextSegment)) + { + MIHP_UNLOCK_HEAP(&heap->HeapLock); + return MIHP_Realloc(heap, ptr, newSize); + } + + MIHP_UNLOCK_HEAP(&heap->HeapLock); + + void* newPtr = MIHP_Allocate(heap, newSize); + if (!newPtr) + return NULL; + + for (size_t i = 0; i < segment->OccupiedSize; i++) + ((char*)newPtr)[i] = ((char*)ptr)[i]; + + MIHP_Free(heap, ptr); + return newPtr; + } + else if (newSize < segment->OccupiedSize) + { + segment->OccupiedSize = newSize; + segment->Checksum = MIHP_GenerateHeapSegmentChecksum(segment); + + size_t alignedNewSize = MIHP_GetHeapAlignedSize(heap, newSize); + size_t minimumPayloadSize = heap->Config.AllocationAlignment; + if (segment->SegmentSize > 2 * segmentHeaderSize + alignedNewSize + minimumPayloadSize) + { + size_t newSplitSegmentSize = segment->SegmentSize - segmentHeaderSize - alignedNewSize; + MIHP_SplitHeapSegment(segment, newSplitSegmentSize, NULL); + } + + MIHP_UNLOCK_HEAP(&heap->HeapLock); + return ptr; + } + + MIHP_UNLOCK_HEAP(&heap->HeapLock); + return ptr; } bool MIHP_Free(MIHP_HeapInfo* heap, void* ptr) @@ -302,7 +372,9 @@ MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_HeapInfo* heap, size_t { MIHP_ASSERT(heap); - size_t effectiveSize = ((requestedSize + MIHP_MINIMAL_MEMORY_AREA_SIZE - 1) / MIHP_MINIMAL_MEMORY_AREA_SIZE) * MIHP_MINIMAL_MEMORY_AREA_SIZE; + size_t effectiveSize = ((requestedSize + heap->Config.MinimalMemoryAreaSize - 1) / heap->Config.MinimalMemoryAreaSize) * heap->Config.MinimalMemoryAreaSize; + effectiveSize = MIHP_MAX(effectiveSize, heap->Config.MinimalMemoryAreaSize); + effectiveSize = MIHP_MIN(effectiveSize, heap->Config.MaximalMemoryAreaSize); MIHP_HeapMemoryAreaHeader* area = MIHP_PlatformRequestMemory(effectiveSize); if (area == NULL) @@ -358,6 +430,8 @@ MIHP_HeapSegmentHeader* MIHP_InitializeHeapSegment(MIHP_HeapMemoryAreaHeader* ar segment->Checksum = ~0; area->NumSegments++; + area->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(area); + area->OwningHeap->Stats.NumTotalSegments++; return segment; @@ -464,37 +538,56 @@ uint32_t MIHP_HashMemoryRegion(const void* data, size_t size) uint32_t MIHP_GenerateHeapMemoryAreaChecksum(const MIHP_HeapMemoryAreaHeader* area) { -#if !MIHP_USE_HEAP_STRUCTURE_CHECKSUM_VALIDATION + +#if MIHP_HEAP_STRUCTURE_VALIDATION_TYPE == MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_NONE return 0; -#endif +#elif MIHP_HEAP_STRUCTURE_VALIDATION_TYPE == MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_MAGIC_NUMBER + return 0xAADEADAA; +#elif MIHP_HEAP_STRUCTURE_VALIDATION_TYPE == MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_CHECKSUM MIHP_ASSERT(area); // Do not include the checksum itself into the new checksum size_t size = offsetof(MIHP_HeapMemoryAreaHeader, Checksum); return MIHP_HashMemoryRegion(area, size); + +#else + #error "Invalid heap structure validation type" +#endif } uint32_t MIHP_GenerateHeapSegmentChecksum(const MIHP_HeapSegmentHeader* segment) { -#if !MIHP_USE_HEAP_STRUCTURE_CHECKSUM_VALIDATION +#if MIHP_HEAP_STRUCTURE_VALIDATION_TYPE == MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_NONE return 0; -#endif +#elif MIHP_HEAP_STRUCTURE_VALIDATION_TYPE == MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_MAGIC_NUMBER + return 0x55DEAD55; +#elif MIHP_HEAP_STRUCTURE_VALIDATION_TYPE == MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_CHECKSUM MIHP_ASSERT(segment); // Do not include the checksum itself into the new checksum size_t size = offsetof(MIHP_HeapSegmentHeader, Checksum); return MIHP_HashMemoryRegion(segment, size); + +#else + #error "Invalid heap structure validation type" +#endif } void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_HeapInfo* heap, const MIHP_HeapMemoryAreaHeader* area) { -#if !MIHP_USE_HEAP_STRUCTURE_CHECKSUM_VALIDATION - return; -#endif + uint32_t newChecksum; - uint32_t newChecksum = MIHP_GenerateHeapMemoryAreaChecksum(area); +#if MIHP_HEAP_STRUCTURE_VALIDATION_TYPE == MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_NONE + return; +#elif MIHP_HEAP_STRUCTURE_VALIDATION_TYPE == MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_MAGIC_NUMBER + newChecksum = 0xAADEADAA; +#elif MIHP_HEAP_STRUCTURE_VALIDATION_TYPE == MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_CHECKSUM + newChecksum = MIHP_GenerateHeapMemoryAreaChecksum(area); +#else + #error "Invalid heap structure validation type" +#endif if (area->Checksum != newChecksum) { @@ -511,11 +604,17 @@ void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_HeapInfo* heap, const MIHP_Hea void MIHP_ValidateHeapSegmentHeader(const MIHP_HeapInfo* heap, const MIHP_HeapSegmentHeader* segment) { -#if !MIHP_USE_HEAP_STRUCTURE_CHECKSUM_VALIDATION - return; -#endif + uint32_t newChecksum; - uint32_t newChecksum = MIHP_GenerateHeapSegmentChecksum(segment); +#if MIHP_HEAP_STRUCTURE_VALIDATION_TYPE == MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_NONE + return; +#elif MIHP_HEAP_STRUCTURE_VALIDATION_TYPE == MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_MAGIC_NUMBER + newChecksum = 0x55DEAD55; +#elif MIHP_HEAP_STRUCTURE_VALIDATION_TYPE == MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_CHECKSUM + newChecksum = MIHP_GenerateHeapSegmentChecksum(segment); +#else + #error "Invalid heap structure validation type" +#endif if (segment->Checksum != newChecksum) { @@ -529,4 +628,3 @@ void MIHP_ValidateHeapSegmentHeader(const MIHP_HeapInfo* heap, const MIHP_HeapSe MIHP_PlatformOnHeapCorruptionDetected(corruptionInfo); } } - diff --git a/minimal_heap.h b/minimal_heap.h index d5b8bd9..a80037b 100644 --- a/minimal_heap.h +++ b/minimal_heap.h @@ -4,8 +4,11 @@ #include #include -#define MIHP_USE_HEAP_STRUCTURE_CHECKSUM_VALIDATION 1 -#define MIHP_USE_CANARY_VALIDATION 1 +#define MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_NONE 0 +#define MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_MAGIC_NUMBER 1 +#define MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_CHECKSUM 2 + +#define MIHP_HEAP_STRUCTURE_VALIDATION_TYPE MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_CHECKSUM #define MIHP_HEAP_CORRUPTION_TYPE_MEMORY_AREA_CHECKSUM_MISMATCH 0 #define MIHP_HEAP_CORRUPTION_TYPE_SEGMENT_CHECKSUM_MISMATCH 1 @@ -80,13 +83,11 @@ void MIHP_PlatformOnHeapCorruptionDetected(MIHP_HeapCorruptionInfo info); /* === */ /* Defines to be configured by the library user */ -#define MIHP_MINIMAL_MEMORY_AREA_SIZE (4096 * 32) - #define MIHP_ASSERT(Condition) while(1) { if (Condition) break; *(volatile char*)(0x0) = 0; } -#define MIHP_HEAP_LOCK_TYPE uint8_t -#define MIHP_LOCK_HEAP(LockVariablePtr) {} -#define MIHP_UNLOCK_HEAP(LockVarialbePtr) {} +#define MIHP_HEAP_LOCK_TYPE uint8_t // Does NOT have to be reentred safe +#define MIHP_LOCK_HEAP(LockVarPtr) { while (*(LockVarPtr)) {}; *(LockVarPtr) = true; } +#define MIHP_UNLOCK_HEAP(LockVarPtr) { *(LockVarPtr) = false; } /* === */ typedef struct _MIHP_HeapInfo diff --git a/minimal_heap_test.c b/minimal_heap_test.c index fb0c76b..371329b 100644 --- a/minimal_heap_test.c +++ b/minimal_heap_test.c @@ -21,7 +21,7 @@ void MIHP_PlatformOnHeapCorruptionDetected(MIHP_HeapCorruptionInfo info) __debugbreak(); } -#define NUM_ALLOCATIONS (4096 * 32) +#define NUM_ALLOCATIONS (4096 * 4) void* myptrs[NUM_ALLOCATIONS] = { 0 }; @@ -67,15 +67,17 @@ int main() for (int i = 0; i < NUM_ALLOCATIONS; i++) { volatile int n = i; - if (!myptrs[i]) + if (myptrs[i]) { - size_t size = 541 + rand() % 2564; + size_t size = 300 + rand() % 500; #if USE_MALLOC - myptrs[i] = malloc(size); + myptrs[i] = realloc(myptrs[i], size); #else - myptrs[i] = MIHP_Allocate(myHeap, size); + myptrs[i] = MIHP_Realloc(myHeap, myptrs[i], size); MIHP_ValidateHeap(myHeap); + + #endif } } From 6d864b3abd8a4298edae65d20fe62c10bccdbe00 Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Mon, 8 Jun 2026 09:32:44 +0200 Subject: [PATCH 12/19] =?UTF-8?q?further=20cleanup=20=F0=9F=97=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- minimal_heap.h | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/minimal_heap.h b/minimal_heap.h index a80037b..0883dc5 100644 --- a/minimal_heap.h +++ b/minimal_heap.h @@ -1,5 +1,7 @@ #pragma once +/* Version 1.0 */ + #include #include #include @@ -8,8 +10,22 @@ #define MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_MAGIC_NUMBER 1 #define MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_CHECKSUM 2 +/* Defines to be configured by the library user */ #define MIHP_HEAP_STRUCTURE_VALIDATION_TYPE MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_CHECKSUM +#define MIHP_ASSERT(Condition) while(1) { if (Condition) break; *(volatile char*)(0x0) = 0; } + +#define MIHP_HEAP_LOCK_TYPE uint8_t // Does NOT have to be reentred safe +#define MIHP_LOCK_HEAP(LockVarPtr) { while (*(LockVarPtr)) {}; *(LockVarPtr) = true; } +#define MIHP_UNLOCK_HEAP(LockVarPtr) { *(LockVarPtr) = false; } +/* */ + +/* 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_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 @@ -76,20 +92,6 @@ typedef struct _MIHP_HeapCorruptionInfo uint32_t ActualValue; } MIHP_HeapCorruptionInfo; -/* 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_PlatformOnHeapCorruptionDetected(MIHP_HeapCorruptionInfo info); -/* === */ - -/* Defines to be configured by the library user */ -#define MIHP_ASSERT(Condition) while(1) { if (Condition) break; *(volatile char*)(0x0) = 0; } - -#define MIHP_HEAP_LOCK_TYPE uint8_t // Does NOT have to be reentred safe -#define MIHP_LOCK_HEAP(LockVarPtr) { while (*(LockVarPtr)) {}; *(LockVarPtr) = true; } -#define MIHP_UNLOCK_HEAP(LockVarPtr) { *(LockVarPtr) = false; } -/* === */ - typedef struct _MIHP_HeapInfo { MIHP_HeapConfig Config; From 546ad3843c447842b92b3589dbfb593dd1df2bbf Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Mon, 8 Jun 2026 09:47:44 +0200 Subject: [PATCH 13/19] changed to semi single header --- minimal_heap.h | 32 +++++++++++++++---- ..._heap.c => minimal_heap_implementation.inl | 2 -- minimal_heap_test.c | 2 ++ minimal_heap_test.vcxproj | 4 ++- minimal_heap_test.vcxproj.filters | 8 +++-- 5 files changed, 35 insertions(+), 13 deletions(-) rename minimal_heap.c => minimal_heap_implementation.inl (99%) diff --git a/minimal_heap.h b/minimal_heap.h index 0883dc5..967087e 100644 --- a/minimal_heap.h +++ b/minimal_heap.h @@ -1,23 +1,35 @@ -#pragma once -/* Version 1.0 */ +/* Version 1.1 */ #include #include #include +#ifndef MIHP_IMPLEMENTATION + #define MIHP_IMPLEMENTATION 0 +#endif + #define MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_NONE 0 #define MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_MAGIC_NUMBER 1 #define MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_CHECKSUM 2 +#ifndef __MINIMAL_HEAP_H__ +#define __MINIMAL_HEAP_H__ + /* Defines to be configured by the library user */ -#define MIHP_HEAP_STRUCTURE_VALIDATION_TYPE MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_CHECKSUM +#ifndef MIHP_HEAP_STRUCTURE_VALIDATION_TYPE + #define MIHP_HEAP_STRUCTURE_VALIDATION_TYPE MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_CHECKSUM +#endif -#define MIHP_ASSERT(Condition) while(1) { if (Condition) break; *(volatile char*)(0x0) = 0; } +#ifndef MIHP_ASSERT + #define MIHP_ASSERT(Condition) while(1) { if (Condition) break; *(volatile char*)(0x0) = 0; } +#endif -#define MIHP_HEAP_LOCK_TYPE uint8_t // Does NOT have to be reentred safe -#define MIHP_LOCK_HEAP(LockVarPtr) { while (*(LockVarPtr)) {}; *(LockVarPtr) = true; } -#define MIHP_UNLOCK_HEAP(LockVarPtr) { *(LockVarPtr) = false; } +#ifndef MIHP_HEAP_LOCK_TYPE + #define MIHP_HEAP_LOCK_TYPE 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 */ @@ -133,3 +145,9 @@ uint32_t MIHP_GenerateHeapSegmentChecksum(const MIHP_HeapSegmentHeader* segment) void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_HeapInfo* heap, const MIHP_HeapMemoryAreaHeader* area); void MIHP_ValidateHeapSegmentHeader(const MIHP_HeapInfo* heap, const MIHP_HeapSegmentHeader* segment); /* */ + +#endif + +#if MIHP_IMPLEMENTATION + #include "minimal_heap_implementation.inl" +#endif diff --git a/minimal_heap.c b/minimal_heap_implementation.inl similarity index 99% rename from minimal_heap.c rename to minimal_heap_implementation.inl index ca5deec..3e4f5bc 100644 --- a/minimal_heap.c +++ b/minimal_heap_implementation.inl @@ -1,5 +1,3 @@ -#include "minimal_heap.h" - #define MIHP_MIN(A, B) (A) < (B) ? (A) : (B) #define MIHP_MAX(A, B) (A) > (B) ? (A) : (B) diff --git a/minimal_heap_test.c b/minimal_heap_test.c index 371329b..a0098c4 100644 --- a/minimal_heap_test.c +++ b/minimal_heap_test.c @@ -1,4 +1,6 @@ +#define MIHP_IMPLEMENTATION 1 #include "minimal_heap.h" + #include #include #include diff --git a/minimal_heap_test.vcxproj b/minimal_heap_test.vcxproj index 9688f30..06693a7 100644 --- a/minimal_heap_test.vcxproj +++ b/minimal_heap_test.vcxproj @@ -124,12 +124,14 @@ - + + + diff --git a/minimal_heap_test.vcxproj.filters b/minimal_heap_test.vcxproj.filters index e9330a5..aad3cae 100644 --- a/minimal_heap_test.vcxproj.filters +++ b/minimal_heap_test.vcxproj.filters @@ -18,13 +18,15 @@ Quelldateien - - Quelldateien - Headerdateien + + + Headerdateien + + \ No newline at end of file From ec12d7c7d7196258a2f050deefd553f5a85dda66 Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Mon, 8 Jun 2026 10:45:57 +0200 Subject: [PATCH 14/19] Update minimal_heap_implementation.inl --- minimal_heap_implementation.inl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/minimal_heap_implementation.inl b/minimal_heap_implementation.inl index 3e4f5bc..c87848d 100644 --- a/minimal_heap_implementation.inl +++ b/minimal_heap_implementation.inl @@ -374,7 +374,7 @@ MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_HeapInfo* heap, size_t effectiveSize = MIHP_MAX(effectiveSize, heap->Config.MinimalMemoryAreaSize); effectiveSize = MIHP_MIN(effectiveSize, heap->Config.MaximalMemoryAreaSize); - MIHP_HeapMemoryAreaHeader* area = MIHP_PlatformRequestMemory(effectiveSize); + MIHP_HeapMemoryAreaHeader* area = (MIHP_HeapMemoryAreaHeader*)MIHP_PlatformRequestMemory(effectiveSize); if (area == NULL) return NULL; From 63a8074a048dab6039a4cd9752addeb354c07d7e Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Mon, 8 Jun 2026 10:58:49 +0200 Subject: [PATCH 15/19] Update minimal_heap_test.c --- minimal_heap_test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/minimal_heap_test.c b/minimal_heap_test.c index a0098c4..62e0d38 100644 --- a/minimal_heap_test.c +++ b/minimal_heap_test.c @@ -7,6 +7,8 @@ #define USE_MALLOC 0 +//#define MIHP_ValidateHeap() + void* MIHP_PlatformRequestMemory(size_t size) { return malloc(size); From 174be6a022a7584d4cb3b057c26f281c628e24c7 Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Mon, 8 Jun 2026 19:20:58 +0200 Subject: [PATCH 16/19] fixed when compacting segment on realloc, the new segment not getting merged with the following empty segment --- minimal_heap.h | 41 ++++++++++++++++----------------- minimal_heap_implementation.inl | 40 +++++++++++++++++--------------- minimal_heap_test.c | 2 +- 3 files changed, 43 insertions(+), 40 deletions(-) diff --git a/minimal_heap.h b/minimal_heap.h index 967087e..f341c7d 100644 --- a/minimal_heap.h +++ b/minimal_heap.h @@ -1,5 +1,7 @@ +/* Version 1.2 */ -/* Version 1.1 */ +#ifndef __MINIMAL_HEAP_H__ +#define __MINIMAL_HEAP_H__ #include #include @@ -13,9 +15,6 @@ #define MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_MAGIC_NUMBER 1 #define MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_CHECKSUM 2 -#ifndef __MINIMAL_HEAP_H__ -#define __MINIMAL_HEAP_H__ - /* 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 @@ -72,7 +71,7 @@ typedef struct _MIHP_HeapMemoryAreaHeader struct _MIHP_HeapMemoryAreaHeader* NextArea; struct _MIHP_HeapMemoryAreaHeader* PreviousArea; - struct _MIHP_HeapInfo* OwningHeap; + struct _MIHP_Heap* OwningHeap; struct _MIHP_HeapSegmentHeader* FirstSegment; @@ -97,14 +96,14 @@ typedef struct _MIHP_HeapSegmentHeader typedef struct _MIHP_HeapCorruptionInfo { - const struct _MIHP_HeapInfo* Heap; + const struct _MIHP_Heap* Heap; uint8_t Type; const void* Ptr; uint32_t ExpectedValue; uint32_t ActualValue; } MIHP_HeapCorruptionInfo; -typedef struct _MIHP_HeapInfo +typedef struct _MIHP_Heap { MIHP_HeapConfig Config; MIHP_HeapStats Stats; @@ -112,23 +111,23 @@ typedef struct _MIHP_HeapInfo MIHP_HeapMemoryAreaHeader* LastSuccessfulAllocationArea; MIHP_HEAP_LOCK_TYPE HeapLock; -} MIHP_HeapInfo; +} MIHP_Heap; /* API Interface */ -MIHP_HeapInfo* MIHP_CreateHeap(MIHP_HeapConfig config); -bool MIHP_DestroyHeap(MIHP_HeapInfo* heap, bool force); -void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size); -void* MIHP_Realloc(MIHP_HeapInfo* heap, void* ptr, size_t newSize); -bool MIHP_Free(MIHP_HeapInfo* heap, void* ptr); +MIHP_Heap* MIHP_CreateHeap(MIHP_HeapConfig config); +bool MIHP_DestroyHeap(MIHP_Heap* heap, bool force); +void* MIHP_Allocate(MIHP_Heap* heap, size_t size); +void* MIHP_Realloc(MIHP_Heap* heap, void* ptr, size_t newSize); +bool MIHP_Free(MIHP_Heap* heap, void* ptr); -bool MIHP_IsPointerInHeap(MIHP_HeapInfo* heap, void* ptr); -size_t MIHP_GetPtrAllocationSize(MIHP_HeapInfo* heap, void* ptr); -void MIHP_ValidateHeap(MIHP_HeapInfo* heap); +bool MIHP_IsPointerInHeap(MIHP_Heap* heap, void* ptr); +size_t MIHP_GetPtrAllocationSize(MIHP_Heap* heap, void* ptr); +void MIHP_ValidateHeap(MIHP_Heap* heap); /* */ /* Internals */ -MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_HeapInfo* heap, size_t requestedSize); -bool MIHP_DestroyHeapMemoryArea(MIHP_HeapInfo* heap, MIHP_HeapMemoryAreaHeader* area); +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); @@ -136,14 +135,14 @@ 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); -size_t MIHP_GetHeapAlignedSize(const MIHP_HeapInfo* heap, size_t size); +size_t MIHP_GetHeapAlignedSize(const MIHP_Heap* heap, size_t size); uint32_t MIHP_HashMemoryRegion(const void* data, size_t size); uint32_t MIHP_GenerateHeapMemoryAreaChecksum(const MIHP_HeapMemoryAreaHeader* area); uint32_t MIHP_GenerateHeapSegmentChecksum(const MIHP_HeapSegmentHeader* segment); -void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_HeapInfo* heap, const MIHP_HeapMemoryAreaHeader* area); -void MIHP_ValidateHeapSegmentHeader(const MIHP_HeapInfo* heap, const MIHP_HeapSegmentHeader* segment); +void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_Heap* heap, const MIHP_HeapMemoryAreaHeader* area); +void MIHP_ValidateHeapSegmentHeader(const MIHP_Heap* heap, const MIHP_HeapSegmentHeader* segment); /* */ #endif diff --git a/minimal_heap_implementation.inl b/minimal_heap_implementation.inl index c87848d..3db0db5 100644 --- a/minimal_heap_implementation.inl +++ b/minimal_heap_implementation.inl @@ -5,7 +5,7 @@ #define MIHP_IS_PO2(Val) (Val != 0 && (Val & (Val - 1)) == 0) -MIHP_HeapInfo* MIHP_CreateHeap(MIHP_HeapConfig config) +MIHP_Heap* MIHP_CreateHeap(MIHP_HeapConfig config) { if (config.AllocationAlignment < sizeof(size_t)) return NULL; @@ -13,11 +13,11 @@ MIHP_HeapInfo* MIHP_CreateHeap(MIHP_HeapConfig config) if (!MIHP_IS_PO2(config.AllocationAlignment)) return NULL; - MIHP_HeapInfo* heap = (MIHP_HeapInfo*)MIHP_PlatformRequestMemory(sizeof(MIHP_HeapInfo)); + MIHP_Heap* heap = (MIHP_Heap*)MIHP_PlatformRequestMemory(sizeof(MIHP_Heap)); if (heap == NULL) return NULL; - MIHP_MEMSET(heap, sizeof(MIHP_HeapInfo), 0); + MIHP_MEMSET(heap, sizeof(MIHP_Heap), 0); heap->Config = config; @@ -25,7 +25,7 @@ MIHP_HeapInfo* MIHP_CreateHeap(MIHP_HeapConfig config) heap->LastSuccessfulAllocationArea = heap->FirstArea; if (heap->FirstArea == NULL) { - MIHP_PlatformFreeMemory(heap, sizeof(MIHP_HeapInfo)); + MIHP_PlatformFreeMemory(heap, sizeof(MIHP_Heap)); return NULL; } @@ -34,7 +34,7 @@ MIHP_HeapInfo* MIHP_CreateHeap(MIHP_HeapConfig config) return heap; } -bool MIHP_DestroyHeap(MIHP_HeapInfo* heap, bool force) +bool MIHP_DestroyHeap(MIHP_Heap* heap, bool force) { if (heap == NULL) return false; @@ -52,11 +52,11 @@ bool MIHP_DestroyHeap(MIHP_HeapInfo* heap, bool force) MIHP_DestroyHeapMemoryArea(heap, currentArea); } - MIHP_PlatformFreeMemory(heap, sizeof(MIHP_HeapInfo)); + MIHP_PlatformFreeMemory(heap, sizeof(MIHP_Heap)); return true; } -void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size) +void* MIHP_Allocate(MIHP_Heap* heap, size_t size) { if (heap == NULL) return NULL; @@ -152,7 +152,7 @@ void* MIHP_Allocate(MIHP_HeapInfo* heap, size_t size) return MIHP_Allocate(heap, size); } -void* MIHP_Realloc(MIHP_HeapInfo* heap, void* ptr, size_t newSize) +void* MIHP_Realloc(MIHP_Heap* heap, void* ptr, size_t newSize) { if (newSize == 0) { @@ -216,7 +216,11 @@ void* MIHP_Realloc(MIHP_HeapInfo* heap, void* ptr, size_t newSize) if (segment->SegmentSize > 2 * segmentHeaderSize + alignedNewSize + minimumPayloadSize) { size_t newSplitSegmentSize = segment->SegmentSize - segmentHeaderSize - alignedNewSize; - MIHP_SplitHeapSegment(segment, newSplitSegmentSize, NULL); + + MIHP_HeapSegmentHeader* newSpittedSegment = NULL; + MIHP_SplitHeapSegment(segment, newSplitSegmentSize, &newSpittedSegment); + if (newSpittedSegment && newSpittedSegment->NextSegment) + MIHP_MergeHeapSegments(newSpittedSegment, newSpittedSegment->NextSegment); } MIHP_UNLOCK_HEAP(&heap->HeapLock); @@ -227,7 +231,7 @@ void* MIHP_Realloc(MIHP_HeapInfo* heap, void* ptr, size_t newSize) return ptr; } -bool MIHP_Free(MIHP_HeapInfo* heap, void* ptr) +bool MIHP_Free(MIHP_Heap* heap, void* ptr) { if (heap == NULL) return false; @@ -304,7 +308,7 @@ bool MIHP_Free(MIHP_HeapInfo* heap, void* ptr) return true; } -bool MIHP_IsPointerInHeap(MIHP_HeapInfo* heap, void* ptr) +bool MIHP_IsPointerInHeap(MIHP_Heap* heap, void* ptr) { if (heap == NULL) return false; @@ -333,7 +337,7 @@ bool MIHP_IsPointerInHeap(MIHP_HeapInfo* heap, void* ptr) return false; } -size_t MIHP_GetPtrAllocationSize(MIHP_HeapInfo* heap, void* ptr) +size_t MIHP_GetPtrAllocationSize(MIHP_Heap* heap, void* ptr) { if (!MIHP_IsPointerInHeap(heap, ptr)) return 0; @@ -347,7 +351,7 @@ size_t MIHP_GetPtrAllocationSize(MIHP_HeapInfo* heap, void* ptr) return segment->OccupiedSize; } -void MIHP_ValidateHeap(MIHP_HeapInfo* heap) +void MIHP_ValidateHeap(MIHP_Heap* heap) { MIHP_HeapMemoryAreaHeader* nextArea = heap->FirstArea; while (nextArea) @@ -366,7 +370,7 @@ void MIHP_ValidateHeap(MIHP_HeapInfo* heap) } } -MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_HeapInfo* heap, size_t requestedSize) +MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_Heap* heap, size_t requestedSize) { MIHP_ASSERT(heap); @@ -394,7 +398,7 @@ MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_HeapInfo* heap, size_t return area; } -bool MIHP_DestroyHeapMemoryArea(MIHP_HeapInfo* heap, MIHP_HeapMemoryAreaHeader* memoryArea) +bool MIHP_DestroyHeapMemoryArea(MIHP_Heap* heap, MIHP_HeapMemoryAreaHeader* memoryArea) { MIHP_ASSERT(heap); MIHP_ASSERT(memoryArea); @@ -516,7 +520,7 @@ bool MIHP_MergeHeapSegments(MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegm return true; } -size_t MIHP_GetHeapAlignedSize(const MIHP_HeapInfo* heap, size_t size) +size_t MIHP_GetHeapAlignedSize(const MIHP_Heap* heap, size_t size) { return (size + (heap->Config.AllocationAlignment - 1)) & ~(heap->Config.AllocationAlignment - 1); } @@ -573,7 +577,7 @@ uint32_t MIHP_GenerateHeapSegmentChecksum(const MIHP_HeapSegmentHeader* segment) #endif } -void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_HeapInfo* heap, const MIHP_HeapMemoryAreaHeader* area) +void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_Heap* heap, const MIHP_HeapMemoryAreaHeader* area) { uint32_t newChecksum; @@ -600,7 +604,7 @@ void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_HeapInfo* heap, const MIHP_Hea } } -void MIHP_ValidateHeapSegmentHeader(const MIHP_HeapInfo* heap, const MIHP_HeapSegmentHeader* segment) +void MIHP_ValidateHeapSegmentHeader(const MIHP_Heap* heap, const MIHP_HeapSegmentHeader* segment) { uint32_t newChecksum; diff --git a/minimal_heap_test.c b/minimal_heap_test.c index 62e0d38..4c194d0 100644 --- a/minimal_heap_test.c +++ b/minimal_heap_test.c @@ -36,7 +36,7 @@ int main() config.AllocationAlignment = 16; config.MinimalMemoryAreaSize = 4096 * 32; config.MaximalMemoryAreaSize = 4096ull * 4096ull * 4096ull; - MIHP_HeapInfo* myHeap = MIHP_CreateHeap(config); + MIHP_Heap* myHeap = MIHP_CreateHeap(config); for (int i = 0; i < NUM_ALLOCATIONS; i++) { From 7095e2abc4277ebd7179a67cf7590e3917e34536 Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Mon, 8 Jun 2026 19:26:21 +0200 Subject: [PATCH 17/19] removed TotalOccupiedSize stats because of inaccuracy --- minimal_heap.h | 1 - minimal_heap_implementation.inl | 4 ---- 2 files changed, 5 deletions(-) diff --git a/minimal_heap.h b/minimal_heap.h index f341c7d..cb59720 100644 --- a/minimal_heap.h +++ b/minimal_heap.h @@ -58,7 +58,6 @@ typedef struct _MIHP_HeapStats size_t NumTotalSegments; size_t NumTotalOccupiedSegments; size_t TotalSize; - size_t TotalOccupiedSize; } MIHP_HeapStats; // This structs size must be multiple of 8 diff --git a/minimal_heap_implementation.inl b/minimal_heap_implementation.inl index 3db0db5..241783c 100644 --- a/minimal_heap_implementation.inl +++ b/minimal_heap_implementation.inl @@ -119,7 +119,6 @@ void* MIHP_Allocate(MIHP_Heap* heap, size_t size) currentArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(currentArea); heap->Stats.NumTotalOccupiedSegments++; - heap->Stats.TotalOccupiedSize += targetSegment->OccupiedSize; heap->LastSuccessfulAllocationArea = currentArea; MIHP_UNLOCK_HEAP(&heap->HeapLock); @@ -251,8 +250,6 @@ bool MIHP_Free(MIHP_Heap* heap, void* ptr) MIHP_HeapMemoryAreaHeader* area = segment->OwningMemoryArea; MIHP_ValidateHeapMemoryAreaHeader(heap, area); - size_t occupiedSize = segment->OccupiedSize; - segment->OccupiedSize = 0; segment->Checksum = MIHP_GenerateHeapSegmentChecksum(segment); @@ -260,7 +257,6 @@ bool MIHP_Free(MIHP_Heap* heap, void* ptr) area->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(area); heap->Stats.NumTotalOccupiedSegments--; - heap->Stats.TotalOccupiedSize -= occupiedSize; if (area->NumOccupiedSegments == 0 && heap->Stats.NumMemoryAreas > 1) { From 6ea22a16e32e0250db1d0f720785161a974c1de4 Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Mon, 8 Jun 2026 19:28:38 +0200 Subject: [PATCH 18/19] more option validation --- minimal_heap.h | 6 +++--- minimal_heap_implementation.inl | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/minimal_heap.h b/minimal_heap.h index cb59720..d7759b3 100644 --- a/minimal_heap.h +++ b/minimal_heap.h @@ -44,10 +44,10 @@ void MIHP_PlatformOnHeapCorruptionDetected(struct _MIHP_HeapCorruptionInfo info) typedef struct _MIHP_HeapConfig { - size_t AllocationAlignment; + size_t AllocationAlignment; // Must be power of two and at least sizeof(size_t) - size_t MinimalMemoryAreaSize; - size_t MaximalMemoryAreaSize; + size_t MinimalMemoryAreaSize; // Must be a multiple of AllocationAlingment + size_t MaximalMemoryAreaSize; // Must be a multiple of AllocationAlingment char AllocationInitialValue; } MIHP_HeapConfig; diff --git a/minimal_heap_implementation.inl b/minimal_heap_implementation.inl index 241783c..4438ee7 100644 --- a/minimal_heap_implementation.inl +++ b/minimal_heap_implementation.inl @@ -13,6 +13,12 @@ MIHP_Heap* MIHP_CreateHeap(MIHP_HeapConfig config) if (!MIHP_IS_PO2(config.AllocationAlignment)) return NULL; + if (config.MinimalMemoryAreaSize % config.AllocationAlignment != 0) + return NULL; + + if (config.MaximalMemoryAreaSize % config.AllocationAlignment != 0) + return NULL; + MIHP_Heap* heap = (MIHP_Heap*)MIHP_PlatformRequestMemory(sizeof(MIHP_Heap)); if (heap == NULL) return NULL; From 69c318ed71c7f35c1a60bc09fe9fa7b3f6acc49a Mon Sep 17 00:00:00 2001 From: ToyB-Chan Date: Mon, 8 Jun 2026 19:37:59 +0200 Subject: [PATCH 19/19] added get minimal payload size function --- minimal_heap.h | 2 ++ minimal_heap_implementation.inl | 11 +++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/minimal_heap.h b/minimal_heap.h index d7759b3..a89c758 100644 --- a/minimal_heap.h +++ b/minimal_heap.h @@ -142,6 +142,8 @@ uint32_t MIHP_GenerateHeapSegmentChecksum(const MIHP_HeapSegmentHeader* segment) void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_Heap* heap, const MIHP_HeapMemoryAreaHeader* area); void MIHP_ValidateHeapSegmentHeader(const MIHP_Heap* heap, const MIHP_HeapSegmentHeader* segment); + +size_t MIHP_GetMinimalPayloadSize(const MIHP_Heap* heap); /* */ #endif diff --git a/minimal_heap_implementation.inl b/minimal_heap_implementation.inl index 4438ee7..592935e 100644 --- a/minimal_heap_implementation.inl +++ b/minimal_heap_implementation.inl @@ -108,10 +108,9 @@ void* MIHP_Allocate(MIHP_Heap* heap, size_t size) continue; size_t segmentHeaderSize = MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapSegmentHeader)); - size_t minimalPayloadSize = heap->Config.AllocationAlignment; MIHP_HeapSegmentHeader* targetSegment = NULL; - if (currentSegment->SegmentSize >= 2 * segmentHeaderSize + size + minimalPayloadSize) + if (currentSegment->SegmentSize >= 2 * segmentHeaderSize + size + MIHP_GetMinimalPayloadSize(heap)) MIHP_SplitHeapSegment(currentSegment, segmentHeaderSize + size, &targetSegment); else if (currentSegment->SegmentSize >= segmentHeaderSize + size) targetSegment = currentSegment; @@ -217,8 +216,7 @@ void* MIHP_Realloc(MIHP_Heap* heap, void* ptr, size_t newSize) segment->Checksum = MIHP_GenerateHeapSegmentChecksum(segment); size_t alignedNewSize = MIHP_GetHeapAlignedSize(heap, newSize); - size_t minimumPayloadSize = heap->Config.AllocationAlignment; - if (segment->SegmentSize > 2 * segmentHeaderSize + alignedNewSize + minimumPayloadSize) + if (segment->SegmentSize > 2 * segmentHeaderSize + alignedNewSize + MIHP_GetMinimalPayloadSize(heap)) { size_t newSplitSegmentSize = segment->SegmentSize - segmentHeaderSize - alignedNewSize; @@ -632,3 +630,8 @@ void MIHP_ValidateHeapSegmentHeader(const MIHP_Heap* heap, const MIHP_HeapSegmen MIHP_PlatformOnHeapCorruptionDetected(corruptionInfo); } } + +size_t MIHP_GetMinimalPayloadSize(const MIHP_Heap* heap) +{ + return heap->Config.AllocationAlignment; +}