mirror of
https://github.com/ToyB-Chan/minimal-heap.git
synced 2026-07-13 21:51:16 +02:00
3
.gitignore
vendored
3
.gitignore
vendored
@@ -50,3 +50,6 @@ modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
# Visual Studio
|
||||
.vs/
|
||||
219
minimal_heap.h
219
minimal_heap.h
@@ -1,110 +1,153 @@
|
||||
#pragma once
|
||||
/* Version 1.2 */
|
||||
|
||||
#ifndef __MINIMAL_HEAP_H__
|
||||
#define __MINIMAL_HEAP_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define USE_HEAP_STRUCTURE_CHECKSUM 1
|
||||
#define 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
|
||||
|
||||
struct heap_stats
|
||||
{
|
||||
size_t num_memory_areas;
|
||||
size_t num_total_segments;
|
||||
size_t num_total_occupied_segments;
|
||||
size_t total_size;
|
||||
} typedef heap_stats;
|
||||
|
||||
struct heap_memory_area
|
||||
{
|
||||
size_t size;
|
||||
size_t num_segments;
|
||||
size_t num_occupied_segments;
|
||||
heap_memory_area* next_area;
|
||||
heap_memory_area* previous_area;
|
||||
|
||||
#if USE_HEAP_STRUCTURE_CHECKSUM
|
||||
uint32_t checksum;
|
||||
#ifndef MIHP_IMPLEMENTATION
|
||||
#define MIHP_IMPLEMENTATION 0
|
||||
#endif
|
||||
} typedef heap_memory_area;
|
||||
|
||||
struct heap_segment
|
||||
{
|
||||
size_t size;
|
||||
bool is_occupied;
|
||||
#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
|
||||
|
||||
heap_segment* next_segment;
|
||||
heap_segment* previous_segment;
|
||||
heap_memory_area* encapsulating_memory_area;
|
||||
|
||||
#if USE_HEAP_STRUCTURE_CHECKSUM
|
||||
uint32_t checksum;
|
||||
/* Defines to be configured by the library user */
|
||||
#ifndef MIHP_HEAP_STRUCTURE_VALIDATION_TYPE
|
||||
#define MIHP_HEAP_STRUCTURE_VALIDATION_TYPE MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_CHECKSUM
|
||||
#endif
|
||||
} typedef heap_segment;
|
||||
|
||||
struct heap_corruption_info
|
||||
{
|
||||
uint8_t type;
|
||||
void* ptr;
|
||||
uint32_t expected_value;
|
||||
uint32_t actual_value;
|
||||
} typedef heap_corruption_info;
|
||||
#ifndef MIHP_ASSERT
|
||||
#define MIHP_ASSERT(Condition) while(1) { if (Condition) break; *(volatile char*)(0x0) = 0; }
|
||||
#endif
|
||||
|
||||
#ifndef MIHP_HEAP_LOCK_TYPE
|
||||
#define MIHP_HEAP_LOCK_TYPE bool // Does NOT have to be reentred safe
|
||||
#define MIHP_LOCK_HEAP(LockVarPtr) { while (*(LockVarPtr)) {}; *(LockVarPtr) = true; }
|
||||
#define MIHP_UNLOCK_HEAP(LockVarPtr) { *(LockVarPtr) = false; }
|
||||
#endif
|
||||
/* */
|
||||
|
||||
/* 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);
|
||||
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);
|
||||
/* */
|
||||
|
||||
size_t config_minimal_memory_area_size();
|
||||
size_t config_minimal_amount_unoccupied_bytes();
|
||||
size_t config_minimal_amount_unoccupied_continuous_bytes();
|
||||
/* === */
|
||||
#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
|
||||
|
||||
uint32_t fast_memory_hasher(const void* data, size_t size)
|
||||
typedef struct _MIHP_HeapConfig
|
||||
{
|
||||
uint32_t hash = 2166136261U;
|
||||
const unsigned char* bytes = (const unsigned char*)data;
|
||||
for (size_t i = 0; i < size; i++)
|
||||
size_t AllocationAlignment; // Must be power of two and at least sizeof(size_t)
|
||||
|
||||
size_t MinimalMemoryAreaSize; // Must be a multiple of AllocationAlingment
|
||||
size_t MaximalMemoryAreaSize; // Must be a multiple of AllocationAlingment
|
||||
|
||||
char AllocationInitialValue;
|
||||
} MIHP_HeapConfig;
|
||||
|
||||
typedef struct _MIHP_HeapStats
|
||||
{
|
||||
hash ^= bytes[i];
|
||||
hash *= 16777619U;
|
||||
}
|
||||
size_t NumMemoryAreas;
|
||||
size_t NumTotalSegments;
|
||||
size_t NumTotalOccupiedSegments;
|
||||
size_t TotalSize;
|
||||
} MIHP_HeapStats;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
uint32_t generate_heap_memory_area_checksum(const heap_memory_area* area)
|
||||
// This structs size must be multiple of 8
|
||||
typedef struct _MIHP_HeapMemoryAreaHeader
|
||||
{
|
||||
size_t checksum_size;
|
||||
size_t AreaSize;
|
||||
size_t NumSegments;
|
||||
size_t NumOccupiedSegments;
|
||||
|
||||
struct _MIHP_HeapMemoryAreaHeader* NextArea;
|
||||
struct _MIHP_HeapMemoryAreaHeader* PreviousArea;
|
||||
|
||||
struct _MIHP_Heap* 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 SegmentSize;
|
||||
size_t OccupiedSize;
|
||||
|
||||
struct _MIHP_HeapSegmentHeader* NextSegment;
|
||||
struct _MIHP_HeapSegmentHeader* PreviousSegment;
|
||||
struct _MIHP_HeapMemoryAreaHeader* OwningMemoryArea;
|
||||
|
||||
char _padding0[16];
|
||||
|
||||
uint32_t Checksum; // Checksum must be the last member !
|
||||
|
||||
} MIHP_HeapSegmentHeader;
|
||||
|
||||
typedef struct _MIHP_HeapCorruptionInfo
|
||||
{
|
||||
const struct _MIHP_Heap* Heap;
|
||||
uint8_t Type;
|
||||
const void* Ptr;
|
||||
uint32_t ExpectedValue;
|
||||
uint32_t ActualValue;
|
||||
} MIHP_HeapCorruptionInfo;
|
||||
|
||||
typedef struct _MIHP_Heap
|
||||
{
|
||||
MIHP_HeapConfig Config;
|
||||
MIHP_HeapStats Stats;
|
||||
MIHP_HeapMemoryAreaHeader* FirstArea;
|
||||
MIHP_HeapMemoryAreaHeader* LastSuccessfulAllocationArea;
|
||||
|
||||
MIHP_HEAP_LOCK_TYPE HeapLock;
|
||||
} MIHP_Heap;
|
||||
|
||||
/* API Interface */
|
||||
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_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_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);
|
||||
|
||||
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_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_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);
|
||||
/* */
|
||||
|
||||
#if USE_HEAP_STRUCTURE_CHECKSUM
|
||||
checksum_size = sizeof(area->checksum);
|
||||
#else
|
||||
checksum_size = 0;
|
||||
#endif
|
||||
|
||||
// Do not include the checksum itself into the new checksum
|
||||
size_t size = sizeof(*area) - checksum_size;
|
||||
return fast_memory_hasher(area, size);
|
||||
}
|
||||
|
||||
uint32_t generate_heap_segment_checksum(const heap_segment* segment)
|
||||
{
|
||||
size_t checksum_size;
|
||||
|
||||
#if USE_HEAP_STRUCTURE_CHECKSUM
|
||||
checksum_size = sizeof(segment->checksum);
|
||||
#else
|
||||
checksum_size = 0;
|
||||
#if MIHP_IMPLEMENTATION
|
||||
#include "minimal_heap_implementation.inl"
|
||||
#endif
|
||||
|
||||
// Do not include the checksum itself into the new checksum
|
||||
size_t size = sizeof(*segment) - checksum_size;
|
||||
return fast_memory_hasher(segment, size);
|
||||
}
|
||||
637
minimal_heap_implementation.inl
Normal file
637
minimal_heap_implementation.inl
Normal file
@@ -0,0 +1,637 @@
|
||||
#define MIHP_MIN(A, B) (A) < (B) ? (A) : (B)
|
||||
#define MIHP_MAX(A, B) (A) > (B) ? (A) : (B)
|
||||
|
||||
#define MIHP_MEMSET(Ptr, Size, Val) for(size_t i = 0; i < Size; ++i) *((char*)Ptr + i) = Val;
|
||||
|
||||
#define MIHP_IS_PO2(Val) (Val != 0 && (Val & (Val - 1)) == 0)
|
||||
|
||||
MIHP_Heap* MIHP_CreateHeap(MIHP_HeapConfig config)
|
||||
{
|
||||
if (config.AllocationAlignment < sizeof(size_t))
|
||||
return NULL;
|
||||
|
||||
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;
|
||||
|
||||
MIHP_MEMSET(heap, sizeof(MIHP_Heap), 0);
|
||||
|
||||
heap->Config = config;
|
||||
|
||||
heap->FirstArea = MIHP_CreateHeapMemoryArea(heap, config.MinimalMemoryAreaSize);
|
||||
heap->LastSuccessfulAllocationArea = heap->FirstArea;
|
||||
if (heap->FirstArea == NULL)
|
||||
{
|
||||
MIHP_PlatformFreeMemory(heap, sizeof(MIHP_Heap));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
heap->FirstArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(heap->FirstArea);
|
||||
|
||||
return heap;
|
||||
}
|
||||
|
||||
bool MIHP_DestroyHeap(MIHP_Heap* heap, bool force)
|
||||
{
|
||||
if (heap == NULL)
|
||||
return false;
|
||||
|
||||
if (!force && heap->Stats.NumTotalOccupiedSegments > 0)
|
||||
return false;
|
||||
|
||||
MIHP_HeapMemoryAreaHeader* nextArea = heap->FirstArea;
|
||||
while (nextArea)
|
||||
{
|
||||
MIHP_HeapMemoryAreaHeader* currentArea = nextArea;
|
||||
MIHP_ValidateHeapMemoryAreaHeader(heap, currentArea);
|
||||
nextArea = currentArea->NextArea;
|
||||
|
||||
MIHP_DestroyHeapMemoryArea(heap, currentArea);
|
||||
}
|
||||
|
||||
MIHP_PlatformFreeMemory(heap, sizeof(MIHP_Heap));
|
||||
return true;
|
||||
}
|
||||
|
||||
void* MIHP_Allocate(MIHP_Heap* heap, size_t size)
|
||||
{
|
||||
if (heap == NULL)
|
||||
return NULL;
|
||||
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
if (size > heap->Config.MaximalMemoryAreaSize)
|
||||
return NULL;
|
||||
|
||||
MIHP_LOCK_HEAP(&heap->HeapLock);
|
||||
|
||||
bool triedLastAllocationArea = false;
|
||||
MIHP_HeapMemoryAreaHeader* nextArea = heap->FirstArea;
|
||||
while (nextArea)
|
||||
{
|
||||
MIHP_HeapMemoryAreaHeader* currentArea = NULL;
|
||||
|
||||
if (!triedLastAllocationArea)
|
||||
{
|
||||
currentArea = heap->LastSuccessfulAllocationArea;
|
||||
triedLastAllocationArea = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentArea = nextArea;
|
||||
nextArea = currentArea->NextArea;
|
||||
}
|
||||
|
||||
MIHP_ValidateHeapMemoryAreaHeader(heap, currentArea);
|
||||
|
||||
if (currentArea->NumOccupiedSegments == currentArea->NumSegments)
|
||||
continue;
|
||||
|
||||
MIHP_HeapSegmentHeader* nextSegment = currentArea->FirstSegment;
|
||||
while (nextSegment)
|
||||
{
|
||||
MIHP_HeapSegmentHeader* currentSegment = nextSegment;
|
||||
MIHP_ValidateHeapSegmentHeader(heap, currentSegment);
|
||||
nextSegment = currentSegment->NextSegment;
|
||||
|
||||
if (currentSegment->OccupiedSize != 0)
|
||||
continue;
|
||||
|
||||
size_t segmentHeaderSize = MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapSegmentHeader));
|
||||
MIHP_HeapSegmentHeader* targetSegment = NULL;
|
||||
|
||||
if (currentSegment->SegmentSize >= 2 * segmentHeaderSize + size + MIHP_GetMinimalPayloadSize(heap))
|
||||
MIHP_SplitHeapSegment(currentSegment, segmentHeaderSize + size, &targetSegment);
|
||||
else if (currentSegment->SegmentSize >= segmentHeaderSize + size)
|
||||
targetSegment = currentSegment;
|
||||
else
|
||||
continue;
|
||||
|
||||
targetSegment->OccupiedSize = size;
|
||||
targetSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(targetSegment);
|
||||
|
||||
currentArea->NumOccupiedSegments++;
|
||||
currentArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(currentArea);
|
||||
|
||||
heap->Stats.NumTotalOccupiedSegments++;
|
||||
heap->LastSuccessfulAllocationArea = currentArea;
|
||||
|
||||
MIHP_UNLOCK_HEAP(&heap->HeapLock);
|
||||
|
||||
void* data = (char*)targetSegment + segmentHeaderSize;
|
||||
MIHP_MEMSET(data, size, heap->Config.AllocationInitialValue);
|
||||
|
||||
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);
|
||||
if (newArea == NULL)
|
||||
return NULL;
|
||||
|
||||
newArea->NextArea = heap->FirstArea;
|
||||
heap->FirstArea->PreviousArea = newArea;
|
||||
heap->FirstArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(heap->FirstArea);
|
||||
|
||||
heap->FirstArea = newArea;
|
||||
heap->LastSuccessfulAllocationArea = newArea;
|
||||
newArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(newArea);
|
||||
|
||||
MIHP_UNLOCK_HEAP(&heap->HeapLock);
|
||||
return MIHP_Allocate(heap, size);
|
||||
}
|
||||
|
||||
void* MIHP_Realloc(MIHP_Heap* heap, void* ptr, size_t newSize)
|
||||
{
|
||||
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);
|
||||
if (segment->SegmentSize > 2 * segmentHeaderSize + alignedNewSize + MIHP_GetMinimalPayloadSize(heap))
|
||||
{
|
||||
size_t newSplitSegmentSize = segment->SegmentSize - segmentHeaderSize - alignedNewSize;
|
||||
|
||||
MIHP_HeapSegmentHeader* newSpittedSegment = NULL;
|
||||
MIHP_SplitHeapSegment(segment, newSplitSegmentSize, &newSpittedSegment);
|
||||
if (newSpittedSegment && newSpittedSegment->NextSegment)
|
||||
MIHP_MergeHeapSegments(newSpittedSegment, newSpittedSegment->NextSegment);
|
||||
}
|
||||
|
||||
MIHP_UNLOCK_HEAP(&heap->HeapLock);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
MIHP_UNLOCK_HEAP(&heap->HeapLock);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool MIHP_Free(MIHP_Heap* heap, void* ptr)
|
||||
{
|
||||
if (heap == NULL)
|
||||
return false;
|
||||
|
||||
if (ptr == NULL)
|
||||
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 = (MIHP_HeapSegmentHeader*)((char*)ptr - segmentHeaderSize);
|
||||
MIHP_ValidateHeapSegmentHeader(heap, segment);
|
||||
|
||||
MIHP_HeapMemoryAreaHeader* area = segment->OwningMemoryArea;
|
||||
MIHP_ValidateHeapMemoryAreaHeader(heap, area);
|
||||
|
||||
segment->OccupiedSize = 0;
|
||||
segment->Checksum = MIHP_GenerateHeapSegmentChecksum(segment);
|
||||
|
||||
area->NumOccupiedSegments--;
|
||||
area->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(area);
|
||||
|
||||
heap->Stats.NumTotalOccupiedSegments--;
|
||||
|
||||
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(heap, prevArea);
|
||||
prevArea->NextArea = nextArea;
|
||||
prevArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(prevArea);
|
||||
}
|
||||
else
|
||||
heap->FirstArea = nextArea;
|
||||
|
||||
if (nextArea)
|
||||
{
|
||||
MIHP_ValidateHeapMemoryAreaHeader(heap, nextArea);
|
||||
nextArea->PreviousArea = prevArea;
|
||||
nextArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(nextArea);
|
||||
}
|
||||
|
||||
MIHP_UNLOCK_HEAP(&heap->HeapLock);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (segment->NextSegment)
|
||||
{
|
||||
MIHP_ValidateHeapSegmentHeader(heap, segment->NextSegment);
|
||||
if (segment->NextSegment->OccupiedSize == 0)
|
||||
MIHP_MergeHeapSegments(segment, segment->NextSegment);
|
||||
}
|
||||
|
||||
if (segment->PreviousSegment)
|
||||
{
|
||||
MIHP_ValidateHeapSegmentHeader(heap, segment->PreviousSegment);
|
||||
if (segment->PreviousSegment->OccupiedSize == 0)
|
||||
MIHP_MergeHeapSegments(segment->PreviousSegment, segment);
|
||||
}
|
||||
|
||||
MIHP_UNLOCK_HEAP(&heap->HeapLock);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MIHP_IsPointerInHeap(MIHP_Heap* heap, void* ptr)
|
||||
{
|
||||
if (heap == NULL)
|
||||
return false;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
size_t MIHP_GetPtrAllocationSize(MIHP_Heap* 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_Heap* heap)
|
||||
{
|
||||
MIHP_HeapMemoryAreaHeader* nextArea = heap->FirstArea;
|
||||
while (nextArea)
|
||||
{
|
||||
MIHP_HeapMemoryAreaHeader* currentArea = nextArea;
|
||||
MIHP_ValidateHeapMemoryAreaHeader(heap, currentArea);
|
||||
nextArea = currentArea->NextArea;
|
||||
|
||||
MIHP_HeapSegmentHeader* nextSegment = currentArea->FirstSegment;
|
||||
while (nextSegment)
|
||||
{
|
||||
MIHP_HeapSegmentHeader* currentSegment = nextSegment;
|
||||
MIHP_ValidateHeapSegmentHeader(heap, currentSegment);
|
||||
nextSegment = currentSegment->NextSegment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_Heap* heap, size_t requestedSize)
|
||||
{
|
||||
MIHP_ASSERT(heap);
|
||||
|
||||
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_HeapMemoryAreaHeader*)MIHP_PlatformRequestMemory(effectiveSize);
|
||||
if (area == NULL)
|
||||
return NULL;
|
||||
|
||||
MIHP_MEMSET(area, sizeof(MIHP_HeapMemoryAreaHeader), 0);
|
||||
|
||||
area->AreaSize = effectiveSize;
|
||||
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;
|
||||
}
|
||||
|
||||
bool MIHP_DestroyHeapMemoryArea(MIHP_Heap* heap, MIHP_HeapMemoryAreaHeader* memoryArea)
|
||||
{
|
||||
MIHP_ASSERT(heap);
|
||||
MIHP_ASSERT(memoryArea);
|
||||
|
||||
size_t areaNumSegments = memoryArea->NumSegments;
|
||||
size_t areaNumOccupiedSegments = memoryArea->NumOccupiedSegments;
|
||||
size_t areaSize = memoryArea->AreaSize;
|
||||
|
||||
if (!MIHP_PlatformFreeMemory(memoryArea, memoryArea->AreaSize))
|
||||
return false;
|
||||
|
||||
heap->Stats.NumTotalSegments -= areaNumSegments;
|
||||
heap->Stats.NumTotalOccupiedSegments -= areaNumOccupiedSegments;
|
||||
heap->Stats.NumMemoryAreas--;
|
||||
heap->Stats.TotalSize -= areaSize;
|
||||
|
||||
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;
|
||||
|
||||
MIHP_MEMSET(segment, sizeof(MIHP_HeapSegmentHeader), 0);
|
||||
|
||||
segment->SegmentSize = segmentSize;
|
||||
segment->OwningMemoryArea = area;
|
||||
segment->Checksum = ~0;
|
||||
|
||||
area->NumSegments++;
|
||||
area->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(area);
|
||||
|
||||
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->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(segment->OwningMemoryArea);
|
||||
segment->OwningMemoryArea->OwningHeap->Stats.NumTotalSegments--;
|
||||
|
||||
MIHP_MEMSET(segment, sizeof(MIHP_HeapSegmentHeader), 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegmentMinSize, MIHP_HeapSegmentHeader** outNewSegment)
|
||||
{
|
||||
MIHP_ASSERT(sourceSegment);
|
||||
|
||||
size_t headerSize = MIHP_GetHeapAlignedSize(sourceSegment->OwningMemoryArea->OwningHeap, sizeof(MIHP_HeapSegmentHeader));
|
||||
size_t effectiveNewSegmentSize = MIHP_GetHeapAlignedSize(sourceSegment->OwningMemoryArea->OwningHeap, newSegmentMinSize);
|
||||
|
||||
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)
|
||||
{
|
||||
MIHP_ValidateHeapSegmentHeader(sourceSegment->OwningMemoryArea->OwningHeap, sourceSegment->NextSegment);
|
||||
sourceSegment->NextSegment->PreviousSegment = newSegment;
|
||||
sourceSegment->NextSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(sourceSegment->NextSegment);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (segmentToAbsorb->OccupiedSize > 0)
|
||||
return false;
|
||||
|
||||
sourceSegment->NextSegment = segmentToAbsorb->NextSegment;
|
||||
|
||||
if (sourceSegment->NextSegment)
|
||||
{
|
||||
MIHP_ValidateHeapSegmentHeader(sourceSegment->OwningMemoryArea->OwningHeap, sourceSegment->NextSegment);
|
||||
sourceSegment->NextSegment->PreviousSegment = sourceSegment;
|
||||
sourceSegment->NextSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(sourceSegment->NextSegment);
|
||||
}
|
||||
|
||||
sourceSegment->SegmentSize += segmentToAbsorb->SegmentSize;
|
||||
MIHP_UninitializeHeapSegment(segmentToAbsorb);
|
||||
|
||||
sourceSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(sourceSegment);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t MIHP_GetHeapAlignedSize(const MIHP_Heap* heap, size_t size)
|
||||
{
|
||||
return (size + (heap->Config.AllocationAlignment - 1)) & ~(heap->Config.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_HEAP_STRUCTURE_VALIDATION_TYPE == MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_NONE
|
||||
return 0;
|
||||
#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_HEAP_STRUCTURE_VALIDATION_TYPE == MIHP_HEAP_STRUCTURE_VALIDATION_TYPE_NONE
|
||||
return 0;
|
||||
#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_Heap* heap, const MIHP_HeapMemoryAreaHeader* area)
|
||||
{
|
||||
uint32_t newChecksum;
|
||||
|
||||
#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)
|
||||
{
|
||||
MIHP_HeapCorruptionInfo corruptionInfo;
|
||||
corruptionInfo.Heap = heap;
|
||||
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_Heap* heap, const MIHP_HeapSegmentHeader* segment)
|
||||
{
|
||||
uint32_t newChecksum;
|
||||
|
||||
#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)
|
||||
{
|
||||
MIHP_HeapCorruptionInfo corruptionInfo;
|
||||
corruptionInfo.Heap = heap;
|
||||
corruptionInfo.Type = MIHP_HEAP_CORRUPTION_TYPE_SEGMENT_CHECKSUM_MISMATCH;
|
||||
corruptionInfo.Ptr = segment;
|
||||
corruptionInfo.ExpectedValue = segment->Checksum;
|
||||
corruptionInfo.ActualValue = newChecksum;
|
||||
|
||||
MIHP_PlatformOnHeapCorruptionDetected(corruptionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
size_t MIHP_GetMinimalPayloadSize(const MIHP_Heap* heap)
|
||||
{
|
||||
return heap->Config.AllocationAlignment;
|
||||
}
|
||||
108
minimal_heap_test.c
Normal file
108
minimal_heap_test.c
Normal file
@@ -0,0 +1,108 @@
|
||||
#define MIHP_IMPLEMENTATION 1
|
||||
#include "minimal_heap.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define USE_MALLOC 0
|
||||
|
||||
//#define MIHP_ValidateHeap()
|
||||
|
||||
void* MIHP_PlatformRequestMemory(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
bool MIHP_PlatformFreeMemory(void* ptr, size_t size)
|
||||
{
|
||||
free(ptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MIHP_PlatformOnHeapCorruptionDetected(MIHP_HeapCorruptionInfo info)
|
||||
{
|
||||
__debugbreak();
|
||||
}
|
||||
|
||||
#define NUM_ALLOCATIONS (4096 * 4)
|
||||
|
||||
void* myptrs[NUM_ALLOCATIONS] = { 0 };
|
||||
|
||||
int main()
|
||||
{
|
||||
MIHP_HeapConfig config = {0};
|
||||
config.AllocationInitialValue = 0xbe;
|
||||
config.AllocationAlignment = 16;
|
||||
config.MinimalMemoryAreaSize = 4096 * 32;
|
||||
config.MaximalMemoryAreaSize = 4096ull * 4096ull * 4096ull;
|
||||
MIHP_Heap* myHeap = MIHP_CreateHeap(config);
|
||||
|
||||
for (int i = 0; i < NUM_ALLOCATIONS; i++)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
if (rand() % 3 == 0)
|
||||
{
|
||||
#if USE_MALLOC
|
||||
free(myptrs[i]);
|
||||
#else
|
||||
MIHP_Free(myHeap, myptrs[i]);
|
||||
MIHP_ValidateHeap(myHeap);
|
||||
#endif
|
||||
|
||||
myptrs[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
__debugbreak();
|
||||
|
||||
for (int i = 0; i < NUM_ALLOCATIONS; i++)
|
||||
{
|
||||
volatile int n = i;
|
||||
if (myptrs[i])
|
||||
{
|
||||
size_t size = 300 + rand() % 500;
|
||||
|
||||
#if USE_MALLOC
|
||||
myptrs[i] = realloc(myptrs[i], size);
|
||||
#else
|
||||
myptrs[i] = MIHP_Realloc(myHeap, myptrs[i], 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();
|
||||
}
|
||||
|
||||
31
minimal_heap_test.sln
Normal file
31
minimal_heap_test.sln
Normal file
@@ -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
|
||||
138
minimal_heap_test.vcxproj
Normal file
138
minimal_heap_test.vcxproj
Normal file
@@ -0,0 +1,138 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{58f662f6-eaac-4d4b-a2f5-c25ed48a05f7}</ProjectGuid>
|
||||
<RootNamespace>minimalheaptest</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard_C>stdc17</LanguageStandard_C>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="minimal_heap_test.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="minimal_heap.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="minimal_heap_implementation.inl" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
32
minimal_heap_test.vcxproj.filters
Normal file
32
minimal_heap_test.vcxproj.filters
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Quelldateien">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Headerdateien">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Ressourcendateien">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="minimal_heap_test.c">
|
||||
<Filter>Quelldateien</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="minimal_heap.h">
|
||||
<Filter>Headerdateien</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="minimal_heap_implementation.inl">
|
||||
<Filter>Headerdateien</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
6
minimal_heap_test.vcxproj.user
Normal file
6
minimal_heap_test.vcxproj.user
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ShowAllFiles>true</ShowAllFiles>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user