From 15b5cc382fd51c4210ebbe564f6a80ef0ee00ce8 Mon Sep 17 00:00:00 2001 From: laentropia Date: Sat, 11 Apr 2026 21:15:31 -0600 Subject: [PATCH] test/refactor: changed things for working with more edge cases --- include/arena.h | 10 ++++-- src/arena.c | 63 +++++++++++++++++++++++++--------- test/test_arena.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 18 deletions(-) diff --git a/include/arena.h b/include/arena.h index e4b65a4..b90b98f 100644 --- a/include/arena.h +++ b/include/arena.h @@ -58,10 +58,16 @@ ArenaErr arena_realloc(Arena *arena, size_t new_capacity); void *arena_unwrap_pointer(ArenaPointer p); SizeResult arena_get_align_padding(Arena *arena, size_t alignment); +// can take big sizes but of sourse there is a limit, +// its protected against SIZE_MAX but anything that +// is big may break it, still, is an edge case that +// I shouldn't cover. ArenaErr arena_ensure_capacity(Arena *arena, size_t size, size_t alignment); + // Should be moved to something like general utilities, // i should make one for all my c projects -bool mul_size_t_safe(size_t a, size_t b, size_t *out); - +static inline bool mul_size_t_safe(size_t a, size_t b, size_t *out); +static inline bool add_size_t_safe(size_t a, size_t b, size_t *out); +static inline bool is_power_of_two(size_t x); #endif // !ARENA_H diff --git a/src/arena.c b/src/arena.c index 3953d1f..0a86219 100644 --- a/src/arena.c +++ b/src/arena.c @@ -70,34 +70,50 @@ ArenaErr arena_ensure_capacity(Arena *arena, size_t size, size_t alignment) { return ARENA_NULL_ARG; } - if (size < 1) { + if (size == 0 || size == SIZE_MAX) { return ARENA_INVALID_SIZE; } - if (alignment < 1) { + if (alignment == 0 || (alignment & (alignment - 1)) != 0) { return ARENA_INVALID_ALIGN; } - - SizeResult padding = arena_get_align_padding(arena, alignment); - if (!padding.is_valid) { - return padding.err; + + SizeResult padding_res = arena_get_align_padding(arena, alignment); + if (!padding_res.is_valid) { + return padding_res.err; } + + size_t padding = padding_res.val; + while (true) { - if (arena->offset > SIZE_MAX - padding.val - size) { + size_t required; + + if (arena->offset > SIZE_MAX - padding) { return ARENA_CAPACITY_OVERFLOW; } + required = arena->offset + padding; - size_t required = arena->offset + padding.val + size; + if (required > SIZE_MAX - size) { + return ARENA_CAPACITY_OVERFLOW; + } + required += size; if (required <= arena->capacity) { return ARENA_OK; } size_t new_capacity; - if (mul_size_t_safe(arena->capacity, 2, &new_capacity)) { + + if (arena->capacity > SIZE_MAX / 2) { return ARENA_CAPACITY_OVERFLOW; } + new_capacity = arena->capacity * 2; + + if (new_capacity < required) { + new_capacity = required; + } + ArenaErr err = arena_realloc(arena, new_capacity); if (err != ARENA_OK) { return err; @@ -159,17 +175,22 @@ ArenaErr arena_realloc(Arena *arena, size_t new_capacity) { SizeResult arena_get_align_padding(Arena *arena, size_t alignment) { if (arena == NULL) { - return (SizeResult) {.is_valid = false, .err = ARENA_NULL_ARG}; + return (SizeResult){ .is_valid = false, .err = ARENA_NULL_ARG }; } - if (alignment < 1) { - return (SizeResult) {.is_valid = false, .err = ARENA_INVALID_ALIGN}; + if (alignment == 0 || (alignment & (alignment - 1)) != 0) { + return (SizeResult){ .is_valid = false, .err = ARENA_INVALID_ALIGN }; } - uintptr_t current_address = (uintptr_t) (arena->buffer + arena->offset); - uintptr_t aligned = ((current_address + (alignment - 1)) & ~(alignment - 1)); + uintptr_t current_address = (uintptr_t)(arena->buffer + arena->offset); - return (SizeResult) {.is_valid = true, .err = aligned - current_address}; + size_t mask = alignment - 1; + size_t padding = (size_t)(-current_address) & mask; + + return (SizeResult){ + .is_valid = true, + .val = padding + }; } void *arena_unwrap_pointer(ArenaPointer p) { @@ -179,7 +200,17 @@ void *arena_unwrap_pointer(ArenaPointer p) { return p.arena->buffer + p.offset; } -bool mul_size_t_safe(size_t a, size_t b, size_t *out) { +static inline bool is_power_of_two(size_t x) { + return x != 0 && (x & (x - 1)) == 0; +} + +static inline bool add_size_t_safe(size_t a, size_t b, size_t *out) { + if (a > SIZE_MAX - b) return true; + *out = a + b; + return false; +} + +static inline bool mul_size_t_safe(size_t a, size_t b, size_t *out) { if (out == NULL) { return true; } diff --git a/test/test_arena.c b/test/test_arena.c index e7eae4c..93190a5 100644 --- a/test/test_arena.c +++ b/test/test_arena.c @@ -108,6 +108,34 @@ static void test_arena_alloc_size_max(void **state) { arena_destroy(&arena); } +static void test_arena_alloc_align_0(void **state) { + (void) state; + + ArenaResult value = arena_init(64); + assert_true(value.is_valid); + Arena arena = value.arena; + + ArenaPointer pointer = arena_alloc(&arena, sizeof(int), 0); + assert_false(pointer.is_valid); + assert_int_equal(pointer.err, ARENA_INVALID_ALIGN); + + arena_destroy(&arena); +} + +static void test_arena_alloc_align_max(void **state) { + (void) state; + + ArenaResult value = arena_init(64); + assert_true(value.is_valid); + Arena arena = value.arena; + + ArenaPointer pointer = arena_alloc(&arena, sizeof(int), SIZE_MAX); + assert_false(pointer.is_valid); + assert_int_equal(pointer.err, ARENA_INVALID_ALIGN); + + arena_destroy(&arena); +} + static void test_arena_align_size_0(void **state) { (void) state; @@ -122,6 +150,58 @@ static void test_arena_align_size_0(void **state) { arena_destroy(&arena); } +static void test_arena_ensure_capacity_size_0(void **state) { + (void) state; + + ArenaResult value = arena_init(64); + assert_true(value.is_valid); + Arena arena = value.arena; + + ArenaErr err = arena_ensure_capacity(&arena, 0, alignof(int)); + assert_int_equal(err, ARENA_INVALID_SIZE); + + arena_destroy(&arena); +} + +static void test_arena_ensure_capacity_size_max(void **state) { + (void) state; + + ArenaResult value = arena_init(64); + assert_true(value.is_valid); + Arena arena = value.arena; + + ArenaErr err = arena_ensure_capacity(&arena, SIZE_MAX, alignof(int)); + assert_int_equal(err, ARENA_INVALID_SIZE); + + arena_destroy(&arena); +} + +static void test_arena_ensure_capacity_align_0(void **state) { + (void) state; + + ArenaResult value = arena_init(64); + assert_true(value.is_valid); + Arena arena = value.arena; + + ArenaErr err = arena_ensure_capacity(&arena, sizeof(int), 0); + assert_int_equal(err, ARENA_INVALID_ALIGN); + + arena_destroy(&arena); +} + +static void test_arena_ensure_capacity_align_max(void **state) { + (void) state; + + ArenaResult value = arena_init(64); + assert_true(value.is_valid); + Arena arena = value.arena; + + ArenaErr err = arena_ensure_capacity(&arena, sizeof(int), SIZE_MAX); + assert_int_equal(err, ARENA_INVALID_ALIGN); + + arena_destroy(&arena); +} + int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_push_3_ints), @@ -129,7 +209,13 @@ int main(void) { cmocka_unit_test(test_init_arena_0_cap), cmocka_unit_test(test_arena_alloc_size_0), cmocka_unit_test(test_arena_alloc_size_max), + cmocka_unit_test(test_arena_alloc_align_0), + cmocka_unit_test(test_arena_alloc_align_max), cmocka_unit_test(test_arena_align_size_0), + cmocka_unit_test(test_arena_ensure_capacity_align_0), + cmocka_unit_test(test_arena_ensure_capacity_align_max), + cmocka_unit_test(test_arena_ensure_capacity_size_0), + cmocka_unit_test(test_arena_ensure_capacity_size_max), };