Compare commits

...

2 Commits

3 changed files with 126 additions and 31 deletions

View File

@@ -58,10 +58,10 @@ ArenaErr arena_realloc(Arena *arena, size_t new_capacity);
void *arena_unwrap_pointer(ArenaPointer p); void *arena_unwrap_pointer(ArenaPointer p);
SizeResult arena_get_align_padding(Arena *arena, size_t alignment); 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); 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);
#endif // !ARENA_H #endif // !ARENA_H

View File

@@ -70,34 +70,50 @@ ArenaErr arena_ensure_capacity(Arena *arena, size_t size, size_t alignment) {
return ARENA_NULL_ARG; return ARENA_NULL_ARG;
} }
if (size < 1) { if (size == 0 || size == SIZE_MAX) {
return ARENA_INVALID_SIZE; return ARENA_INVALID_SIZE;
} }
if (alignment < 1) { if (alignment == 0 || (alignment & (alignment - 1)) != 0) {
return ARENA_INVALID_ALIGN; return ARENA_INVALID_ALIGN;
} }
SizeResult padding = arena_get_align_padding(arena, alignment); SizeResult padding_res = arena_get_align_padding(arena, alignment);
if (!padding.is_valid) { if (!padding_res.is_valid) {
return padding.err; return padding_res.err;
} }
size_t padding = padding_res.val;
while (true) { while (true) {
if (arena->offset > SIZE_MAX - padding.val - size) { size_t required;
if (arena->offset > SIZE_MAX - padding) {
return ARENA_CAPACITY_OVERFLOW; 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) { if (required <= arena->capacity) {
return ARENA_OK; return ARENA_OK;
} }
size_t new_capacity; size_t new_capacity;
if (mul_size_t_safe(arena->capacity, 2, &new_capacity)) {
if (arena->capacity > SIZE_MAX / 2) {
return ARENA_CAPACITY_OVERFLOW; return ARENA_CAPACITY_OVERFLOW;
} }
new_capacity = arena->capacity * 2;
if (new_capacity < required) {
new_capacity = required;
}
ArenaErr err = arena_realloc(arena, new_capacity); ArenaErr err = arena_realloc(arena, new_capacity);
if (err != ARENA_OK) { if (err != ARENA_OK) {
return err; 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) { SizeResult arena_get_align_padding(Arena *arena, size_t alignment) {
if (arena == NULL) { if (arena == NULL) {
return (SizeResult) {.is_valid = false, .err = ARENA_NULL_ARG}; return (SizeResult){ .is_valid = false, .err = ARENA_NULL_ARG };
} }
if (alignment < 1) { if (alignment == 0 || (alignment & (alignment - 1)) != 0) {
return (SizeResult) {.is_valid = false, .err = ARENA_INVALID_ALIGN}; return (SizeResult){ .is_valid = false, .err = ARENA_INVALID_ALIGN };
} }
uintptr_t current_address = (uintptr_t) (arena->buffer + arena->offset); uintptr_t current_address = (uintptr_t)(arena->buffer + arena->offset);
uintptr_t aligned = ((current_address + (alignment - 1)) & ~(alignment - 1));
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) { void *arena_unwrap_pointer(ArenaPointer p) {
@@ -179,16 +200,4 @@ void *arena_unwrap_pointer(ArenaPointer p) {
return p.arena->buffer + p.offset; return p.arena->buffer + p.offset;
} }
bool mul_size_t_safe(size_t a, size_t b, size_t *out) {
if (out == NULL) {
return true;
}
if (a != 0 && b > SIZE_MAX / a) {
return true;
}
*out = a * b;
return false;
}

View File

@@ -108,6 +108,34 @@ static void test_arena_alloc_size_max(void **state) {
arena_destroy(&arena); 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) { static void test_arena_align_size_0(void **state) {
(void) state; (void) state;
@@ -122,6 +150,58 @@ static void test_arena_align_size_0(void **state) {
arena_destroy(&arena); 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) { int main(void) {
const struct CMUnitTest tests[] = { const struct CMUnitTest tests[] = {
cmocka_unit_test(test_push_3_ints), 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_init_arena_0_cap),
cmocka_unit_test(test_arena_alloc_size_0), cmocka_unit_test(test_arena_alloc_size_0),
cmocka_unit_test(test_arena_alloc_size_max), 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_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),
}; };