From c31aff806dea2b35e26cdd197e50fc4163016dac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 7 Jun 2026 02:27:56 +0200 Subject: [PATCH] Add mmap allocator --- build.sh | 2 +- src/arena.c | 49 +++++++++++++++++++++++++++---------------------- src/arena.h | 23 +++++++---------------- src/base_core.h | 32 ++++++++++++++++++++++++-------- src/main.c | 16 ++++++++++++---- src/platform.c | 37 +++++++++++++++++++++++++++++++++++++ src/platform.h | 8 ++++++++ 7 files changed, 116 insertions(+), 51 deletions(-) create mode 100644 src/platform.c create mode 100644 src/platform.h diff --git a/build.sh b/build.sh index b4be581..e1d0aba 100755 --- a/build.sh +++ b/build.sh @@ -1,3 +1,3 @@ #!/bin/sh set -x -gcc -fsanitize=address -ggdb -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -std=gnu23 $CFLAGS src/*c +clang-19 -pipe -fsanitize=address -ggdb -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -std=gnu23 $CFLAGS src/*c diff --git a/src/arena.c b/src/arena.c index e05648e..cc5b4c0 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1,17 +1,6 @@ #include "arena.h" #include "base_core.h" -#include -// -//note(nos) Move to platrofm layer -static void *memory_allocate(size_t sz) -{ - return malloc(sz); -} - -static void memory_release(void *mem) -{ - free(mem); -} +#include "platform.h" static INLINE U32 arena_absolute_pos(const Arena *arena) { @@ -19,23 +8,28 @@ static INLINE U32 arena_absolute_pos(const Arena *arena) return current->base_pos + current->pos; } -Arena *arena_alloc_(const ArenaParams *params) +Arena *arena_alloc(const ArenaParams *params) { Assert(params->size > ARENA_HEADER_SZ); Assert(params->size < (U32_Max - ARENA_HEADER_SZ - 1)); // Note: only backend now is malloc - void *base = memory_allocate(params->size); - //((U8*)base)[1023+ARENA_HEADER_SZ] = 1; - + void *base; + if (params->flags & ArenaFlag_UseMalloc){ + base = platform_malloc(params->size); + } else { + base = memory_allocate(params->size); + } Assert(base != NULL); + ASAN_UNPOISON_MEMORY_REGION(base, ARENA_HEADER_SZ); Arena *arena = (Arena *)base; - arena->base = base; + arena->base = (U8 *)base; arena->current = arena; arena->size = params->size; arena->pos = ARENA_HEADER_SZ; arena->base_pos = 0; + arena->flags = params->flags; arena->prev = NULL; arena->checkpoint_level = 0; @@ -49,7 +43,11 @@ void arena_free(Arena *arena) while (it != NULL) { Arena *prev = it->prev; - memory_release(it); + if (it->flags & ArenaFlag_UseMalloc){ + platform_free(it->base); + } else { + memory_free(it->base, it->size); + } it = prev; } } @@ -58,6 +56,7 @@ void *arena_push(Arena *arena, U32 size, U32 align) { Assert(size < (U32_Max - align - ARENA_HEADER_SZ - 1)); Assert(IsPow2(align)); + Arena *current = arena->current; U32 start_pos = AlignUpPow2(current->pos, align); U32 available = arena_available(current); @@ -72,7 +71,7 @@ void *arena_push(Arena *arena, U32 size, U32 align) new_params.flags = current->flags; new_params.size = new_size; - Arena *new_arena = arena_alloc_(&new_params); + Arena *new_arena = arena_alloc(&new_params); new_arena->base_pos = current->base_pos + current->size; new_arena->prev = current; arena->current = new_arena; @@ -98,8 +97,13 @@ void arena_pop_to(Arena *arena, U32 abs_pos) Arena *prev = current->prev; if (current->base_pos >= abs_pos) { - ASAN_UNPOISON_MEMORY_REGION(current->base, current->size); - memory_release(current->base); + ASAN_UNPOISON_MEMORY_REGION(current->base, current->size); // needed as we use malloc + if (current->flags & ArenaFlag_UseMalloc){ + platform_free(current->base); + } else { + memory_free(current->base, current->size); + } + arena->current = prev; } else { U32 new_pos = abs_pos - current->base_pos; @@ -121,14 +125,15 @@ ArenaCheckPoint arena_temp_begin(Arena *arena) checkpoint.arena = arena; checkpoint.absolute_pos = arena_absolute_pos(arena); arena->checkpoint_level++; + return checkpoint; } void arena_temp_end(ArenaCheckPoint *checkpoint) { Arena *arena = checkpoint->arena; - arena_pop_to(arena, checkpoint->absolute_pos); Assert(arena->checkpoint_level > 0); + arena_pop_to(arena, checkpoint->absolute_pos); arena->checkpoint_level--; } diff --git a/src/arena.h b/src/arena.h index f493fd0..2f12367 100644 --- a/src/arena.h +++ b/src/arena.h @@ -1,25 +1,13 @@ #pragma once #include "base_core.h" -#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) -#include -#define ASAN_POISON_MEMORY_REGION(addr, size) \ - __asan_poison_memory_region((addr), (size)) -#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \ - __asan_unpoison_memory_region((addr), (size)) -#else -#define ASAN_POISON_MEMORY_REGION(addr, size) \ - ((void)(addr), (void)(size)) -#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \ - ((void)(addr), (void)(size)) -#endif typedef U32 ArenaFlags; +enum { + ArenaFlag_UseMalloc = (1 << 0), +}; typedef struct ArenaParams ArenaParams; -enum { - ArenaFlag_UseMalloc = (1 << 0), -}; struct ArenaParams { U32 size; ArenaFlags flags; // No flags defined yet @@ -52,10 +40,13 @@ static INLINE U32 arena_available(const Arena *arena) return arena->size - arena->pos; } -Arena *arena_alloc_(const ArenaParams *params); +Arena *arena_alloc(const ArenaParams *params); void arena_free(Arena *arena); void *arena_push(Arena *arena, U32 size, U32 align); +#define arena_push_type(arena, type) arena_push(arena, (U32)sizeof(type), alignof(type)) +#define arena_push_array_of(arena, type, len) arena_push(arena, (U32) (sizeof(type) * (len)), alignof(type)) + ArenaCheckPoint arena_temp_begin(Arena *arena); void arena_temp_end(ArenaCheckPoint *checkpoint); void arena_pop_to(Arena *arena, U32 abs_pos); diff --git a/src/base_core.h b/src/base_core.h index ae62c85..c2da7c8 100644 --- a/src/base_core.h +++ b/src/base_core.h @@ -49,6 +49,8 @@ typedef unsigned __int128 U128; // asserts #define Trap() __builtin_trap() +#define Abort() __builtin_abort() + #define Assert(x) do { if (!(x)) { Trap(); }} while(0) #define NotImplemented Assert(!"Not Implemented") @@ -71,7 +73,7 @@ typedef unsigned __int128 U128; _amn < _bmn ? _amn : _bmn; \ }) -#define ArraySize(a) (sizeof(a) / sizeof(a[0])) +#define ArraySize(a) (sizeof(a) / sizeof((a)[0])) #define Swap(a, b) \ do { \ @@ -133,8 +135,8 @@ typedef unsigned __int128 U128; /** * Round x up to nearest multiple of y - * e.g. ROUND_UP(30,48) == 48 - * e.g. ROUND_UP(49,48) == 96 + * e.g. RoundUp(30,48) == 48 + * e.g. RoundUp(49,48) == 96 * * @param x numerator, must be positive * @param y denominator @@ -144,8 +146,8 @@ typedef unsigned __int128 U128; /** * Round x down to nearest multiple of y - * e.g. ROUND_UP(30,48) == 0 - * e.g. ROUND_UP(49,48) == 48 + * e.g. RoundDown(30,48) == 0 + * e.g. RoundDown(49,48) == 48 * * @param x numerator, must be positive * @param y denominator @@ -194,15 +196,15 @@ typedef unsigned __int128 U128; #define MemoryZero(ptr, len) explicit_bzero(ptr, len) #endif #define MemMove(dst, src, len) memmove(dst, src, len) -#define MemCpy(dst, src, len) memcpy(dst, src, len) +#define MemCopy(dst, src, len) memcpy(dst, src, len) #define MemAppend(dst, src, len) mempcpy(dst, src, len) // atomics #define Atomic(type) _Atomic(type) #define AtomicSub(ptr, val) __atomic_fetch_sub((ptr), (val), __ATOMIC_SEQ_CST) #define AtomicAdd(ptr, val) __atomic_fetch_add((ptr), (val), __ATOMIC_SEQ_CST) -#define AtomicDec(ptr) UC_ATOMIC_SUB((ptr), 1) -#define AtomicInc(ptr) UC_ATOMIC_ADD((ptr), 1) +#define AtomicDec(ptr) AtomicSub((ptr), 1) +#define AtomicInc(ptr) AtomicAdd((ptr), 1) #define AtomicGet(ptr) __c11_atomic_load((ptr), __ATOMIC_SEQ_CST) #define AtomicCAS(ptr, oldval, newval) \ __atomic_compare_exchange((ptr), (oldval), (newval),0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) @@ -290,3 +292,17 @@ static INLINE U64 SaturatingMult64(U64 a, U64 b) return SaturatingMult(a, b, U64, U64_Max); } +// address-sanitizer helpers (-fsanitize=address) + +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) +#include +#define ASAN_POISON_MEMORY_REGION(addr, size) \ + __asan_poison_memory_region((addr), (size)) +#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \ + __asan_unpoison_memory_region((addr), (size)) +#else +#define ASAN_POISON_MEMORY_REGION(addr, size) \ + ((void)(addr), (void)(size)) +#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \ + ((void)(addr), (void)(size)) +#endif diff --git a/src/main.c b/src/main.c index ae11172..397130f 100644 --- a/src/main.c +++ b/src/main.c @@ -22,9 +22,9 @@ static void arena_test_1(void) { ArenaParams arena_params = {}; arena_params.size = 1024+ARENA_HEADER_SZ; - Arena *arena = arena_alloc_(&arena_params); + Arena *arena = arena_alloc(&arena_params); arena_dump(arena); - char *ptr = arena_push(arena, 512, 1); + void *ptr = arena_push(arena, 512, 1); MemoryZero(ptr, 512); printf("Allocated ptr %p\n", ptr); arena_dump(arena); @@ -43,27 +43,35 @@ static void arena_test_2(void) { ArenaParams arena_params = {}; arena_params.size = 1024+ARENA_HEADER_SZ; - Arena *arena = arena_alloc_(&arena_params); + arena_params.flags = ArenaFlag_UseMalloc; + Arena *arena = arena_alloc(&arena_params); void *ptr; ptr = arena_push(arena, 1024, 8); + MemoryZero(ptr, 1024); printf("Allocated ptr %p\n", ptr); arena_dump(arena); ArenaCheckPoint checkpoint = arena_temp_begin(arena); ptr = arena_push(arena, 4096, 8); + MemoryZero(ptr, 4096); + ptr = arena_push(arena, 4096, 8); + MemoryZero(ptr, 4096); ArenaCheckPoint checkpoint2 = arena_temp_begin(arena); ptr = arena_push(arena, 64, 8); + MemoryZero(ptr, 64); + arena_temp_end(&checkpoint2); arena_temp_end(&checkpoint); arena_pop_to(arena, 1088); arena_dump(arena); ptr = arena_push(arena, 1, 1); - ((U8*)ptr)[1] =1; //OOB + ((U8*)ptr)[0] = 0x37; ptr = arena_push(arena, 1, 1); + ((U8*)ptr)[0] = 0x73; arena_pop_to(arena, 1089); arena_dump(arena); diff --git a/src/platform.c b/src/platform.c new file mode 100644 index 0000000..5afde47 --- /dev/null +++ b/src/platform.c @@ -0,0 +1,37 @@ +#include "base_core.h" +#include +#include +#include + +void *platform_malloc(size_t sz) +{ + return malloc(sz); +} + +void platform_free(void *mem) +{ + free(mem); +} + + +void *memory_allocate(size_t sz) +{ + int page_size = getpagesize(); + size_t aligned_sz = AlignUpPow2(sz, page_size); + + void *mem = mmap(0, aligned_sz, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (mem == MAP_FAILED) { + mem = NULL; + } + return mem; +} + +void memory_free(void *mem, size_t sz) +{ + int page_size = getpagesize(); + size_t aligned_sz = AlignUpPow2(sz, page_size); + + int rc = munmap(mem, aligned_sz); + + Assert(rc == 0); +} diff --git a/src/platform.h b/src/platform.h new file mode 100644 index 0000000..ed80ba0 --- /dev/null +++ b/src/platform.h @@ -0,0 +1,8 @@ +#pragma once +#include + +void *platform_malloc(size_t sz); +void platform_free(void *mem); + +void *memory_allocate(size_t sz); +void *memory_free(void *mem, size_t sz);