Compare commits

13 Commits

Author SHA1 Message Date
a632291f07 bump version 2026-11-05 18:09:27 +01:00
dcd6c58394 fixed some bugs (tm) 2026-11-05 17:57:07 +01:00
77630e2c47 fixed bad struct size on 64 bit for custom metadata 2026-07-11 05:04:03 +02:00
2289ec8644 more asserts 2026-06-14 04:17:03 +02:00
088a3648dd forward declaration 2026-06-14 04:05:45 +02:00
a78ec329b4 asdx 2026-06-14 03:24:40 +02:00
394e42aae8 ifdef 2026-06-14 03:21:15 +02:00
9f42297bf2 Update minimal_heap_implementation.inl 2026-06-14 03:04:02 +02:00
92eb9456bc a 2026-06-13 23:43:20 +02:00
947ea6698d changed memset signature and added freefillvalue 2026-06-13 23:33:41 +02:00
164493cdac Update minimal_heap_implementation.inl 2026-06-13 23:21:18 +02:00
cda05cd84b bump version 2026-06-13 23:18:00 +02:00
d000447369 Merge pull request #3 from ToyB-Chan/error-results
added error results
2026-06-13 23:16:55 +02:00
3 changed files with 44 additions and 36 deletions

View File

@@ -2,30 +2,26 @@
#define __MINIMAL_HEAP_H__ #define __MINIMAL_HEAP_H__
#define MIHP_VERSION_MAJOR 1 #define MIHP_VERSION_MAJOR 1
#define MIHP_VERSION_MINOR 10 #define MIHP_VERSION_MINOR 13
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#ifndef MIHP_IMPLEMENTATION
#define MIHP_IMPLEMENTATION 0
#endif
/* Defines to be configured by the library user */ /* Defines to be configured by the library user */
#ifndef MIHP_ASSERT #ifndef MIHP_ASSERT
#define MIHP_ASSERT(Condition) while(1) { if (Condition) break; *(volatile char*)(0x0) = 0; } #define MIHP_ASSERT(Condition) while(1) { if (Condition) break; *(volatile char*)(0x0) = 0; }
#endif #endif
#ifndef MIHP_MEMSET #ifndef MIHP_MEMSET
#define MIHP_MEMSET(Ptr, Size, Val) do { for(size_t i = 0; i < Size; ++i) *((char*)Ptr + i) = Val; } while(0); #define MIHP_MEMSET(Ptr, Val, Size) do { for(size_t i = 0; i < Size; ++i) *((char*)Ptr + i) = Val; } while(0);
#endif #endif
/* */ /* */
typedef uintptr_t MIHP_HeapOpaque; typedef uintptr_t MIHP_HeapOpaque;
typedef void*(MIHP_PlatformRequestMemoryFn)(MIHP_HeapOpaque heap, size_t minRequestedSize, size_t* outActualSize); typedef void*(MIHP_PlatformRequestMemoryFn)(MIHP_HeapOpaque heap, size_t minRequestedSize, size_t* outActualSize);
typedef bool (MIHP_PlatformFreeMemoryFn)(MIHP_HeapOpaque heap, void* Ptr, size_t actualSize); typedef bool (MIHP_PlatformFreeMemoryFn)(MIHP_HeapOpaque heap, void* ptr, size_t actualSize);
typedef enum _MIHP_HeapCorruptionError typedef enum _MIHP_HeapCorruptionError
{ {
@@ -34,6 +30,9 @@ typedef enum _MIHP_HeapCorruptionError
MIHP_HCE_DoubleFree = 2 MIHP_HCE_DoubleFree = 2
} MIHP_HeapCorruptionError; } MIHP_HeapCorruptionError;
struct _MIHP_Heap;
struct _MIHP_HeapCorruptionInfo;
typedef void (MIHP_OnHeapCorruptionDetectedFn)(const struct _MIHP_Heap* heap, struct _MIHP_HeapCorruptionInfo corruptionInfo); typedef void (MIHP_OnHeapCorruptionDetectedFn)(const struct _MIHP_Heap* heap, struct _MIHP_HeapCorruptionInfo corruptionInfo);
typedef void(MIHP_LockHeapFn)(MIHP_HeapOpaque heap, void* heapLock); typedef void(MIHP_LockHeapFn)(MIHP_HeapOpaque heap, void* heapLock);
@@ -76,7 +75,9 @@ typedef struct _MIHP_HeapConfig
uint8_t MinHeapTraversalPercentToExpand; // Minimal integer percent of the heap traversed before expanding the heap uint8_t MinHeapTraversalPercentToExpand; // Minimal integer percent of the heap traversed before expanding the heap
size_t AllocationAlignment; // Must be power of two and at least sizeof(size_t) size_t AllocationAlignment; // Must be power of two and at least sizeof(size_t)
uint8_t AllocationInitialValue; // Initial value the returned blocks are to be filled with
uint8_t AllocateFillValue; // Initial value the returned blocks are to be filled with
uint8_t FreeFillValue; // Value freed blocks are to be filled with
MIHP_HeapValidationMode HeapValidationMode; MIHP_HeapValidationMode HeapValidationMode;
@@ -116,10 +117,10 @@ typedef struct _MIHP_AllocationCustomMetadata
union union
{ {
uint8_t AsU8 [sizeof(size_t) * 2]; uint8_t AsU8 [sizeof(size_t) * 2];
uint16_t AsU16 [sizeof(size_t) * 1]; uint16_t AsU16 [(sizeof(size_t) * 2) / sizeof(uint16_t)];
uint32_t AsU32 [sizeof(size_t) / 2]; uint32_t AsU32 [(sizeof(size_t) * 2) / sizeof(uint32_t)];
void* AsPtr [sizeof(size_t) / 2]; void* AsPtr [(sizeof(size_t) * 2) / sizeof(void*)];
uint64_t AsU64 [sizeof(size_t) / 4]; uint64_t AsU64 [(sizeof(size_t) * 2) / sizeof(uint64_t)];
}; };
} MIHP_AllocationCustomMetadata; } MIHP_AllocationCustomMetadata;
@@ -208,7 +209,7 @@ size_t MIHP_GetMinimalPayloadSize(const MIHP_Heap* heap);
size_t MIHP_GetMaximalPayloadSize(const MIHP_Heap* heap); size_t MIHP_GetMaximalPayloadSize(const MIHP_Heap* heap);
/* */ /* */
#if MIHP_IMPLEMENTATION #ifdef MIHP_IMPLEMENTATION
#include "minimal_heap_implementation.inl" #include "minimal_heap_implementation.inl"
#endif #endif

View File

@@ -1,4 +1,3 @@
#include "minimal_heap.h"
#define MIHP_MIN(A, B) ((A) < (B) ? (A) : (B)) #define MIHP_MIN(A, B) ((A) < (B) ? (A) : (B))
#define MIHP_MAX(A, B) ((A) > (B) ? (A) : (B)) #define MIHP_MAX(A, B) ((A) > (B) ? (A) : (B))
@@ -22,9 +21,10 @@ MIHP_HeapConfig MIHP_MakeDefaultConfigPreset()
cfg.MinHeapTraversalPercentToExpand = 80; cfg.MinHeapTraversalPercentToExpand = 80;
cfg.AllocationAlignment = 16; cfg.AllocationAlignment = 16;
cfg.AllocationInitialValue = 0xbe; cfg.AllocateFillValue = 0xbe;
cfg.FreeFillValue = 0xee;
cfg.HeapValidationMode = MIHP_HVM_MagicNumber; cfg.HeapValidationMode = MIHP_HVM_None;
return cfg; return cfg;
} }
@@ -43,6 +43,12 @@ MIHP_HeapError MIHP_InitializeHeap(MIHP_Heap* heap, MIHP_HeapConfig config)
if (config.PlatformFreeMemoryFn == NULL) if (config.PlatformFreeMemoryFn == NULL)
return MIHP_HE_BadConfig; return MIHP_HE_BadConfig;
if (config.OnHeapCorruptionDetectedFn == NULL && config.HeapValidationMode != MIHP_HVM_None)
return MIHP_HE_BadConfig;
if (config.MinMemoryAreaSize < MIHP_GetMinimalPayloadSize(heap) * 2)
return MIHP_HE_BadConfig;
if (config.MaxHeapSize < config.MinMemoryAreaSize) if (config.MaxHeapSize < config.MinMemoryAreaSize)
return MIHP_HE_BadConfig; return MIHP_HE_BadConfig;
@@ -73,7 +79,7 @@ MIHP_HeapError MIHP_InitializeHeap(MIHP_Heap* heap, MIHP_HeapConfig config)
return MIHP_HE_BadConfig; return MIHP_HE_BadConfig;
} }
MIHP_MEMSET(heap, sizeof(MIHP_Heap), 0); MIHP_MEMSET(heap, 0, sizeof(MIHP_Heap));
heap->Config = config; heap->Config = config;
heap->FirstArea = MIHP_CreateHeapMemoryArea(heap, config.MinMemoryAreaSize); heap->FirstArea = MIHP_CreateHeapMemoryArea(heap, config.MinMemoryAreaSize);
@@ -112,7 +118,7 @@ MIHP_HeapError MIHP_UninitializeHeap(MIHP_Heap* heap, bool force)
MIHP_DestroyHeapMemoryArea(heap, currentArea); MIHP_DestroyHeapMemoryArea(heap, currentArea);
} }
MIHP_MEMSET(heap, sizeof(MIHP_Heap), 0); MIHP_MEMSET(heap, 0, sizeof(MIHP_Heap));
return MIHP_HE_Success; return MIHP_HE_Success;
} }
@@ -190,7 +196,7 @@ MIHP_HeapResult MIHP_Allocate(MIHP_Heap* heap, size_t size)
MIHP_UnlockHeap(heap); MIHP_UnlockHeap(heap);
void* data = MIHP_GetHeapSegmentPayloadPtr(heap, targetSegment); void* data = MIHP_GetHeapSegmentPayloadPtr(heap, targetSegment);
MIHP_MEMSET(data, size, heap->Config.AllocationInitialValue); MIHP_MEMSET(data, heap->Config.AllocateFillValue, size);
return MIHP_MAKE_RESULT(data, MIHP_HE_Success); return MIHP_MAKE_RESULT(data, MIHP_HE_Success);
} while (nextSegment != currentArea->LastSuccessfulAllocationSegment); } while (nextSegment != currentArea->LastSuccessfulAllocationSegment);
@@ -255,12 +261,12 @@ MIHP_HeapResult MIHP_Reallocate(MIHP_Heap* heap, void* ptr, size_t newSize)
size_t maxPayloadSize = segment->SegmentSize - segmentHeaderSize; size_t maxPayloadSize = segment->SegmentSize - segmentHeaderSize;
if (newSize <= maxPayloadSize) if (newSize <= maxPayloadSize)
{ {
MIHP_MEMSET((char*)ptr + segment->OccupiedSize, newSize - segment->OccupiedSize, heap->Config.AllocationInitialValue); MIHP_MEMSET((char*)ptr + segment->OccupiedSize, heap->Config.AllocateFillValue, newSize - segment->OccupiedSize);
segment->OccupiedSize = newSize; segment->OccupiedSize = newSize;
segment->Checksum = MIHP_GenerateHeapSegmentChecksum(heap, segment); segment->Checksum = MIHP_GenerateHeapSegmentChecksum(heap, segment);
MIHP_UnlockHeap(heap); MIHP_UnlockHeap(heap);
return MIHP_MAKE_RESULT(NULL, MIHP_HE_Success); return MIHP_MAKE_RESULT(ptr, MIHP_HE_Success);
} }
if (segment->NextSegment) if (segment->NextSegment)
@@ -289,6 +295,8 @@ MIHP_HeapResult MIHP_Reallocate(MIHP_Heap* heap, void* ptr, size_t newSize)
} }
else if (newSize < segment->OccupiedSize) else if (newSize < segment->OccupiedSize)
{ {
MIHP_MEMSET((char*)ptr + newSize, heap->Config.FreeFillValue, segment->OccupiedSize - newSize);
segment->OccupiedSize = newSize; segment->OccupiedSize = newSize;
segment->Checksum = MIHP_GenerateHeapSegmentChecksum(heap, segment); segment->Checksum = MIHP_GenerateHeapSegmentChecksum(heap, segment);
@@ -325,17 +333,18 @@ MIHP_HeapError MIHP_Free(MIHP_Heap* heap, void* ptr)
if (segment->OccupiedSize == 0) if (segment->OccupiedSize == 0)
{ {
MIHP_HeapCorruptionInfo corruptionInfo = { 0 }; MIHP_HeapCorruptionInfo corruptionInfo;
corruptionInfo.Error = MIHP_HCE_DoubleFree; corruptionInfo.Error = MIHP_HCE_DoubleFree;
corruptionInfo.Ptr = ptr; corruptionInfo.Ptr = ptr;
corruptionInfo.ExpectedValue = 0;
corruptionInfo.ActualValue = 0;
if (heap->Config.OnHeapCorruptionDetectedFn != NULL) if (heap->Config.OnHeapCorruptionDetectedFn != NULL)
heap->Config.OnHeapCorruptionDetectedFn(heap, corruptionInfo); heap->Config.OnHeapCorruptionDetectedFn(heap, corruptionInfo);
MIHP_UnlockHeap(heap);
return MIHP_HE_InvalidOperation;
} }
MIHP_MEMSET(ptr, heap->Config.FreeFillValue, segment->OccupiedSize);
segment->OccupiedSize = 0; segment->OccupiedSize = 0;
segment->Checksum = MIHP_GenerateHeapSegmentChecksum(heap, segment); segment->Checksum = MIHP_GenerateHeapSegmentChecksum(heap, segment);
@@ -399,6 +408,7 @@ MIHP_HeapError MIHP_SetPointerCustomMetadata(MIHP_Heap* heap, void* ptr, MIHP_Al
MIHP_HeapSegmentHeader* segment = MIHP_GetHeapSegmentHeaderPtr(heap, ptr); MIHP_HeapSegmentHeader* segment = MIHP_GetHeapSegmentHeaderPtr(heap, ptr);
MIHP_ValidateHeapSegmentHeader(heap, segment); MIHP_ValidateHeapSegmentHeader(heap, segment);
segment->CustomMetadata = metadata; segment->CustomMetadata = metadata;
segment->Checksum = MIHP_GenerateHeapSegmentChecksum(heap, segment);
return MIHP_HE_Success; return MIHP_HE_Success;
} }
@@ -463,7 +473,7 @@ MIHP_HeapError MIHP_MergeHeaps(MIHP_Heap* sourceHeap, MIHP_Heap* heapToAbsorb)
sourceHeap->Stats.TotalSize += heapToAbsorb->Stats.TotalSize; sourceHeap->Stats.TotalSize += heapToAbsorb->Stats.TotalSize;
MIHP_UnlockHeap(heapToAbsorb); MIHP_UnlockHeap(heapToAbsorb);
MIHP_MEMSET(heapToAbsorb, sizeof(MIHP_Heap), 0); MIHP_MEMSET(heapToAbsorb, 0, sizeof(MIHP_Heap));
sourceEndArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(sourceHeap, sourceEndArea); sourceEndArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(sourceHeap, sourceEndArea);
sourceEndArea->NextArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(sourceHeap, sourceEndArea->NextArea); sourceEndArea->NextArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(sourceHeap, sourceEndArea->NextArea);
@@ -607,8 +617,11 @@ MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_Heap* heap, size_t req
if (area == NULL) if (area == NULL)
return NULL; return NULL;
MIHP_ASSERT((uintptr_t)area % heap->Config.AllocationAlignment == 0);
MIHP_ASSERT(actualSize % heap->Config.AllocationAlignment == 0);
MIHP_ASSERT(actualSize >= effectiveSize); MIHP_ASSERT(actualSize >= effectiveSize);
MIHP_MEMSET(area, sizeof(MIHP_HeapMemoryAreaHeader), 0);
MIHP_MEMSET(area, 0, sizeof(MIHP_HeapMemoryAreaHeader));
area->InstigatingHeap = (MIHP_HeapOpaque)heap; area->InstigatingHeap = (MIHP_HeapOpaque)heap;
area->AreaSize = actualSize; area->AreaSize = actualSize;
@@ -652,7 +665,7 @@ MIHP_HeapSegmentHeader* MIHP_InitializeHeapSegment(MIHP_Heap* heap, MIHP_HeapMem
MIHP_HeapSegmentHeader* segment = (MIHP_HeapSegmentHeader*)segmentStart; MIHP_HeapSegmentHeader* segment = (MIHP_HeapSegmentHeader*)segmentStart;
MIHP_MEMSET(segment, sizeof(MIHP_HeapSegmentHeader), 0); MIHP_MEMSET(segment, 0, sizeof(MIHP_HeapSegmentHeader));
segment->SegmentSize = segmentSize; segment->SegmentSize = segmentSize;
segment->OwningMemoryArea = area; segment->OwningMemoryArea = area;
@@ -677,7 +690,7 @@ bool MIHP_UninitializeHeapSegment(MIHP_Heap* heap, MIHP_HeapSegmentHeader* segme
segment->OwningMemoryArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(heap, segment->OwningMemoryArea); segment->OwningMemoryArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(heap, segment->OwningMemoryArea);
heap->Stats.NumTotalSegments--; heap->Stats.NumTotalSegments--;
MIHP_MEMSET(segment, sizeof(MIHP_HeapSegmentHeader), 0); MIHP_MEMSET(segment, 0, sizeof(MIHP_HeapSegmentHeader));
return true; return true;
} }
@@ -823,9 +836,6 @@ uint32_t MIHP_GenerateHeapSegmentChecksum(const MIHP_Heap* heap, const MIHP_Heap
void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_Heap* heap, const MIHP_HeapMemoryAreaHeader* area) void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_Heap* heap, const MIHP_HeapMemoryAreaHeader* area)
{ {
if (heap->Config.OnHeapCorruptionDetectedFn == NULL)
return;
uint32_t newChecksum; uint32_t newChecksum;
if (heap->Config.HeapValidationMode == MIHP_HVM_None) if (heap->Config.HeapValidationMode == MIHP_HVM_None)
@@ -852,9 +862,6 @@ void MIHP_ValidateHeapMemoryAreaHeader(const MIHP_Heap* heap, const MIHP_HeapMem
void MIHP_ValidateHeapSegmentHeader(const MIHP_Heap* heap, const MIHP_HeapSegmentHeader* segment) void MIHP_ValidateHeapSegmentHeader(const MIHP_Heap* heap, const MIHP_HeapSegmentHeader* segment)
{ {
if (heap->Config.OnHeapCorruptionDetectedFn == NULL)
return;
uint32_t newChecksum; uint32_t newChecksum;
if (heap->Config.HeapValidationMode == MIHP_HVM_None) if (heap->Config.HeapValidationMode == MIHP_HVM_None)

View File

@@ -1,4 +1,4 @@
#define MIHP_IMPLEMENTATION 1 #define MIHP_IMPLEMENTATION
#include "minimal_heap.h" #include "minimal_heap.h"
#include <stdlib.h> #include <stdlib.h>