From 7fce434af70a6e5386a63fd6547d41050e9db6e8 Mon Sep 17 00:00:00 2001 From: Thomas Spader Date: Wed, 10 Jun 2026 05:36:31 -0400 Subject: [PATCH] mem: various arena fixes The allocator interface now requires a size for realloc() and free(). This was always an error; sp_sys_free() required a size, and all of our allocators implemented headers to track allocation sizes. The glue between them, the interface, simply omitted it. In doing this, we were able to get rid of the headers that all the allocators had to implement. This drastically simplified the arena allocator, as well as fixed most of the longstanding issues that I have had with it. Likewise for the page allocator. I also added some small things: - test: Updated the tracking allocator used for leak testing to now verify what was actually allocated and find mismatches - io: Added sp_io_dyn_mem_writer_take_str(), which reallocates the buffer so its length and capacity match, allowing it to be returned as a string which can be freed without the writer. - io: sp_io_read_file() shrinks the buffer when a file reads short - mem: Unrelated overflow checks in the arena - mem: Arenas no longer crash on OOM - test: Rewrote arena tests declaratively - test: Added tests for the fixed allocator --- sp.h | 386 +++++++++++++++++++++++--------------------- sp/sp_asset.h | 6 +- sp/sp_prompt.h | 4 +- test/array.c | 2 +- test/bench/heap.c | 32 ++-- test/bench/ubench.h | 11 +- test/ht.c | 2 +- test/leak.c | 30 ++-- test/mem/arena.c | 237 +++++++++++++++------------ test/mem/builtin.c | 16 +- test/mem/fixed.c | 43 ++++- test/mem/heap.c | 4 +- test/prompt.c | 2 +- test/tools/stress.c | 8 +- test/tools/test.h | 35 ++-- test/tools/utest.h | 74 ++++++--- tools/wip/sp_elf.h | 4 +- 17 files changed, 509 insertions(+), 387 deletions(-) diff --git a/sp.h b/sp.h index 6c62666..efb3b43 100644 --- a/sp.h +++ b/sp.h @@ -1452,7 +1452,7 @@ typedef enum { SP_TYPEDEF_FN( void*, sp_allocator_fn_t, - void* user_data, sp_mem_alloc_mode_t mode, u64 size, void* ptr + void* user_data, sp_mem_alloc_mode_t mode, u64 size, void* ptr, u64 old_size ); typedef struct sp_allocator_t { @@ -1461,11 +1461,11 @@ typedef struct sp_allocator_t { } sp_mem_t; SP_API void* sp_mem_allocator_alloc(sp_mem_t arena, u64 size); -SP_API void* sp_mem_allocator_realloc(sp_mem_t arena, void* ptr, u64 size); -SP_API void sp_mem_allocator_free(sp_mem_t arena, void* buffer); +SP_API void* sp_mem_allocator_realloc(sp_mem_t arena, void* ptr, u64 old_size, u64 size); +SP_API void sp_mem_allocator_free(sp_mem_t arena, void* buffer, u64 size); SP_API void* sp_alloc(sp_mem_t mem, u64 size); -SP_API void* sp_realloc(sp_mem_t mem, void* memory, u64 size); -SP_API void sp_free(sp_mem_t mem, void* memory); +SP_API void* sp_realloc(sp_mem_t mem, void* memory, u64 old_size, u64 size); +SP_API void sp_free(sp_mem_t mem, void* memory, u64 size); SP_API sp_mem_t sp_mem_get_scratch(); ////////// @@ -1501,33 +1501,24 @@ SP_API sp_mem_fixed_t sp_mem_fixed_ex(void* buffer, u64 capacity, u8 alignment); SP_API sp_mem_t sp_mem_fixed_as_allocator(sp_mem_fixed_t* fixed); SP_API void sp_mem_fixed_clear(sp_mem_fixed_t* fixed); SP_API u64 sp_mem_fixed_bytes_used(sp_mem_fixed_t* fixed); -SP_API void* sp_mem_fixed_on_alloc(void* ud, sp_mem_alloc_mode_t mode, u64 size, void* old); +SP_API void* sp_mem_fixed_on_alloc(void* ud, sp_mem_alloc_mode_t mode, u64 size, void* old, u64 old_size); //////////////////// // PAGE ALLOCATOR // //////////////////// -typedef struct SP_ALIGNED { - u64 size; -} sp_mem_os_header_t; - SP_API void* sp_mem_os_alloc(u64 size); -SP_API void* sp_mem_os_realloc(void* ptr, u64 size); -SP_API void sp_mem_os_free(void* ptr); -SP_API void* sp_mem_os_on_alloc(void* ud, sp_mem_alloc_mode_t mode, u64 size, void* ptr); -SP_API sp_mem_os_header_t* sp_mem_os_get_header(void* ptr); +SP_API void* sp_mem_os_realloc(void* ptr, u64 old_size, u64 size); +SP_API void sp_mem_os_free(void* ptr, u64 size); +SP_API void* sp_mem_os_on_alloc(void* ud, sp_mem_alloc_mode_t mode, u64 size, void* ptr, u64 old_size); SP_API sp_mem_t sp_mem_os_new(); ///////////////////// // ARENA ALLOCATOR // ///////////////////// -typedef enum { - SP_MEM_ARENA_MODE_DEFAULT, - SP_MEM_ARENA_MODE_NO_REALLOC, -} sp_mem_arena_mode_t; +#define SP_MEM_ARENA_MAX_BLOCK_SIZE (1 << 20) -typedef struct sp_mem_arena_block_t { +typedef struct SP_ALIGNED sp_mem_arena_block_t { struct sp_mem_arena_block_t* next; - u8* buffer; u64 capacity; u64 bytes_used; } sp_mem_arena_block_t; @@ -1537,7 +1528,6 @@ typedef struct { sp_mem_arena_block_t* head; sp_mem_arena_block_t* current; u64 block_size; - sp_mem_arena_mode_t mode; u8 alignment; } sp_mem_arena_t; @@ -1549,18 +1539,18 @@ typedef struct { } sp_mem_arena_marker_t; SP_API sp_mem_arena_t* sp_mem_arena_new(sp_mem_t mem); -SP_API sp_mem_arena_t* sp_mem_arena_new_ex(sp_mem_t mem, u64 block_size, sp_mem_arena_mode_t mode, u8 alignment); +SP_API sp_mem_arena_t* sp_mem_arena_new_ex(sp_mem_t mem, u64 block_size, u8 alignment); SP_API sp_mem_t sp_mem_arena_as_allocator(sp_mem_arena_t* arena); SP_API void sp_mem_arena_clear(sp_mem_arena_t* arena); SP_API void sp_mem_arena_destroy(sp_mem_arena_t* arena); -SP_API void* sp_mem_arena_on_alloc(void* ptr, sp_mem_alloc_mode_t mode, u64 n, void* old); +SP_API void* sp_mem_arena_on_alloc(void* ptr, sp_mem_alloc_mode_t mode, u64 n, void* old, u64 old_size); SP_API sp_mem_arena_marker_t sp_mem_arena_mark(sp_mem_arena_t* a); SP_API void sp_mem_arena_pop(sp_mem_arena_marker_t marker); SP_API u64 sp_mem_arena_capacity(sp_mem_arena_t* arena); SP_API u64 sp_mem_arena_bytes_used(sp_mem_arena_t* arena); SP_API void* sp_mem_arena_alloc(sp_mem_arena_t* arena, u64 size); -SP_API void* sp_mem_arena_realloc(sp_mem_arena_t* arena, void* ptr, u64 size); -SP_API void sp_mem_arena_free(sp_mem_arena_t* arena, void* ptr); +SP_API void* sp_mem_arena_realloc(sp_mem_arena_t* arena, void* ptr, u64 old_size, u64 size); +SP_API void sp_mem_arena_free(sp_mem_arena_t* arena, void* ptr, u64 size); SP_API sp_mem_arena_t* sp_mem_get_scratch_arena(); SP_API sp_mem_arena_t* sp_mem_get_scratch_arena_for(sp_mem_t mem); SP_API sp_mem_arena_marker_t sp_mem_begin_scratch(); @@ -1675,7 +1665,7 @@ typedef struct sp_mem_heap_t { SP_API sp_mem_heap_t* sp_mem_heap_new(); SP_API void sp_mem_heap_destroy(sp_mem_heap_t* heap); SP_API sp_mem_t sp_mem_heap_as_allocator(sp_mem_heap_t* heap); -SP_API void* sp_mem_heap_on_alloc(void* ud, sp_mem_alloc_mode_t mode, u64 size, void* ptr); +SP_API void* sp_mem_heap_on_alloc(void* ud, sp_mem_alloc_mode_t mode, u64 size, void* ptr, u64 old_size); SP_API void* sp_mem_heap_alloc(sp_mem_heap_t* heap, u64 size); SP_API void* sp_mem_heap_realloc(sp_mem_heap_t* heap, void* ptr, u64 size); SP_API void sp_mem_heap_free(sp_mem_heap_t* heap, void* ptr); @@ -1783,7 +1773,7 @@ SP_API void sp_da_push_ex(void** arr, void* val, u32 stride); ((__T*)sp_da_init_ex((__a), sizeof(__T))) #define sp_da_free(__arr) \ - sp_mem_allocator_free(sp_da_mem(__arr), sp_da_head(__arr)) + sp_mem_allocator_free(sp_da_mem(__arr), sp_da_head(__arr), sp_da_capacity(__arr) * sp_da_stride(__arr) + sizeof(sp_da_header_t)) #define sp_da_grow(__ARR, __N)\ sp_da_grow_ex((__ARR), sp_da_stride(__ARR), (__N)) @@ -1876,7 +1866,7 @@ SP_API void* sp_rb_grow_ex(void* arr, u32 stride, u32 new_cap); #define sp_rb_free(__ARR)\ do {\ if (__ARR) {\ - sp_mem_allocator_free(sp_rb_mem(__ARR), sp_rb_head(__ARR));\ + sp_mem_allocator_free(sp_rb_mem(__ARR), sp_rb_head(__ARR), sp_rb_capacity(__ARR) * sizeof(*(__ARR)) + sizeof(sp_ring_buffer_t));\ (__ARR) = SP_NULLPTR;\ }\ } while (0) @@ -2095,9 +2085,9 @@ SP_BEGIN_EXTERN_C() #define sp_ht_free(ht) \ do { \ if ((ht)) { \ - sp_mem_allocator_free((ht)->info.allocator, (ht)->data); \ + sp_mem_allocator_free((ht)->info.allocator, (ht)->data, (ht)->capacity * sizeof((ht)->data[0])); \ (ht)->data = SP_NULLPTR;\ - sp_mem_allocator_free((ht)->info.allocator, (ht)); \ + sp_mem_allocator_free((ht)->info.allocator, (ht), sizeof(*(ht))); \ (ht) = SP_NULLPTR; \ } \ } while (0) @@ -3432,6 +3422,7 @@ SP_API sp_err_t sp_io_dyn_mem_writer_seek(sp_io_dyn_mem_writer_t* w, s64 o SP_API sp_err_t sp_io_dyn_mem_writer_size(sp_io_dyn_mem_writer_t* w, u64* size); SP_API sp_err_t sp_io_dyn_mem_writer_close(sp_io_dyn_mem_writer_t* w); SP_API sp_str_t sp_io_dyn_mem_writer_as_str(sp_io_dyn_mem_writer_t* w); +SP_API sp_str_t sp_io_dyn_mem_writer_take_str(sp_io_dyn_mem_writer_t* w); SP_API const c8* sp_io_dyn_mem_writer_as_cstr(sp_io_dyn_mem_writer_t* w); SP_API sp_io_stream_writer_t sp_io_get_std_out(); @@ -3747,11 +3738,9 @@ SP_IMP sp_fmt_arg_t sp_fmt_arg_from_argv(sp_fmt_argv_t v); SP_IMP sp_hash_t sp_hash_str(sp_str_t str); // @memory -SP_IMP sp_mem_arena_block_t* sp_mem_arena_block_new(sp_mem_arena_t* arena, u64 capacity); -SP_IMP void* sp_mem_arena_align_block(sp_mem_arena_block_t* block, u8 alignment); -SP_IMP sp_mem_arena_block_t* sp_mem_arena_get_block(sp_mem_arena_t* arena, u64 alloc_size); -SP_IMP void* sp_mem_arena_alloc_with_header(sp_mem_arena_t* arena, u64 size); -SP_IMP void* sp_mem_arena_alloc_no_header(sp_mem_arena_t* arena, u64 size); +SP_IMP sp_mem_arena_block_t* sp_mem_arena_block_new(sp_mem_arena_t* arena, u64 block_size); +SP_IMP u64 sp_mem_arena_block_align(sp_mem_arena_block_t* block, u8 alignment); +SP_IMP sp_mem_arena_block_t* sp_mem_arena_get_block(sp_mem_arena_t* arena, u64 size); SP_IMP u32 sp_mem_heap_bucket_of(u64 size); SP_IMP u64 sp_mem_heap_bucket_size(u32 bucket); SP_IMP void sp_mem_heap_track_reserve(sp_mem_heap_t* heap, u64 bytes); @@ -6930,7 +6919,7 @@ void sp_ht_resize_impl(void** data, u64 old_cap, u64 new_cap, sp_ht_info_t info) *(sp_ht_entry_state*)((c8*)new_data + new_idx * info.stride.entry + info.stride.kv) = SP_HT_ENTRY_ACTIVE; } - sp_free(info.allocator, old_data); + sp_free(info.allocator, old_data, old_cap * info.stride.entry); *data = new_data; } @@ -7021,7 +7010,8 @@ void* sp_da_resize(void* arr, u32 stride, u64 cap) { cap = sp_max(cap, 4); sp_da_header_t* header = sp_da_head(arr); - header = sp_cast(sp_da_header_t*, sp_realloc(header->allocator, header, cap * stride + sizeof(sp_da_header_t))); + u64 old_size = header->capacity * stride + sizeof(sp_da_header_t); + header = sp_cast(sp_da_header_t*, sp_realloc(header->allocator, header, old_size, cap * stride + sizeof(sp_da_header_t))); if (!header) return SP_NULLPTR; @@ -7110,7 +7100,7 @@ void* sp_rb_grow_ex(void* arr, u32 stride, u32 capacity) { sp_mem_copy(new_arr + first_chunk * stride, old_arr, second_chunk * stride); } - sp_mem_allocator_free(mem, old); + sp_mem_allocator_free(mem, old, old_cap * stride + sizeof(sp_ring_buffer_t)); return (u8*)(rb + 1); } @@ -8003,8 +7993,8 @@ void sp_rt_init() { void sp_tls_rt_deinit(void* ptr) { if (!ptr) return; sp_tls_rt_t* tls = (sp_tls_rt_t*)ptr; - if (tls->std.out) sp_mem_allocator_free(tls->mem, tls->std.out); - if (tls->std.err) sp_mem_allocator_free(tls->mem, tls->std.err); + if (tls->std.out) sp_mem_allocator_free(tls->mem, tls->std.out, sizeof(sp_io_stream_writer_t)); + if (tls->std.err) sp_mem_allocator_free(tls->mem, tls->std.err, sizeof(sp_io_stream_writer_t)); sp_str_ht_free(tls->format.directives); sp_carr_for(tls->scratch, it) { sp_mem_arena_destroy(tls->scratch[it]); @@ -8168,45 +8158,49 @@ void sp_tls_once(sp_tls_once_t* once, sp_tls_once_fn_t fn) { // @memory void* sp_mem_allocator_alloc(sp_mem_t allocator, u64 size) { - return allocator.on_alloc(allocator.user_data, SP_ALLOCATOR_MODE_ALLOC, size, NULL); + return allocator.on_alloc(allocator.user_data, SP_ALLOCATOR_MODE_ALLOC, size, NULL, 0); } -void* sp_mem_allocator_realloc(sp_mem_t allocator, void* memory, u64 size) { - return allocator.on_alloc(allocator.user_data, SP_ALLOCATOR_MODE_RESIZE, size, memory); +void* sp_mem_allocator_realloc(sp_mem_t allocator, void* memory, u64 old_size, u64 size) { + return allocator.on_alloc(allocator.user_data, SP_ALLOCATOR_MODE_RESIZE, size, memory, old_size); } -void sp_mem_allocator_free(sp_mem_t allocator, void* buffer) { - allocator.on_alloc(allocator.user_data, SP_ALLOCATOR_MODE_FREE, 0, buffer); +void sp_mem_allocator_free(sp_mem_t allocator, void* buffer, u64 size) { + allocator.on_alloc(allocator.user_data, SP_ALLOCATOR_MODE_FREE, 0, buffer, size); } -typedef struct { - u64 size; - u8 padding [8]; -} sp_mem_arena_header_t; +u8* sp_mem_arena_block_buffer(sp_mem_arena_block_t* block) { + return (u8*)(block + 1); +} -sp_mem_arena_block_t* sp_mem_arena_block_new(sp_mem_arena_t* arena, u64 capacity) { - sp_mem_arena_block_t* block = sp_mem_allocator_alloc_type(arena->allocator, sp_mem_arena_block_t); +sp_mem_arena_block_t* sp_mem_arena_block_new(sp_mem_arena_t* arena, u64 block_size) { + sp_mem_arena_block_t* block = (sp_mem_arena_block_t*)sp_mem_allocator_alloc(arena->allocator, block_size); + if (!block) return SP_NULLPTR; block->next = SP_NULLPTR; - block->buffer = sp_mem_allocator_alloc_n(arena->allocator, u8, capacity); - block->capacity = capacity; + block->capacity = block_size - sizeof(sp_mem_arena_block_t); block->bytes_used = 0; return block; } sp_mem_arena_t* sp_mem_arena_new(sp_mem_t mem) { - return sp_mem_arena_new_ex(mem, 4096, SP_MEM_ARENA_MODE_DEFAULT, SP_MEM_ALIGNMENT); + return sp_mem_arena_new_ex(mem, 4096, SP_MEM_ALIGNMENT); } -sp_mem_arena_t* sp_mem_arena_new_ex(sp_mem_t mem, u64 block_size, sp_mem_arena_mode_t mode, u8 alignment) { +sp_mem_arena_t* sp_mem_arena_new_ex(sp_mem_t mem, u64 block_size, u8 alignment) { sp_mem_arena_t* arena = (sp_mem_arena_t*)sp_mem_allocator_alloc(mem, sizeof(sp_mem_arena_t)); + if (!arena) return SP_NULLPTR; arena->allocator = mem; - arena->mode = mode; arena->alignment = alignment == 0 ? SP_MEM_ALIGNMENT : alignment; + sp_assert((arena->alignment & (arena->alignment - 1)) == 0); + arena->block_size = sp_max(block_size, sizeof(sp_mem_arena_block_t) + arena->alignment); - sp_mem_arena_block_t* block = sp_mem_arena_block_new(arena, block_size); + sp_mem_arena_block_t* block = sp_mem_arena_block_new(arena, arena->block_size); + if (!block) { + sp_mem_allocator_free(mem, arena, sizeof(sp_mem_arena_t)); + return SP_NULLPTR; + } arena->head = block; arena->current = block; - arena->block_size = block_size; return arena; } @@ -8226,16 +8220,13 @@ void sp_mem_arena_destroy(sp_mem_arena_t* arena) { sp_mem_arena_block_t* block = arena->head; while (block) { sp_mem_arena_block_t* next = block->next; - if (block->buffer) { - sp_mem_allocator_free(arena->allocator, block->buffer); - } - sp_mem_allocator_free(arena->allocator, block); + sp_mem_allocator_free(arena->allocator, block, sizeof(sp_mem_arena_block_t) + block->capacity); block = next; } arena->head = SP_NULLPTR; arena->current = SP_NULLPTR; - sp_mem_allocator_free(arena->allocator, arena); + sp_mem_allocator_free(arena->allocator, arena, sizeof(sp_mem_arena_t)); } u64 sp_mem_arena_capacity(sp_mem_arena_t* arena) { @@ -8255,94 +8246,101 @@ u64 sp_mem_arena_bytes_used(sp_mem_arena_t* arena) { return total; } -sp_mem_arena_header_t* sp_mem_arena_get_header(void* ptr) { - return (sp_mem_arena_header_t*)((u8*)ptr - sizeof(sp_mem_arena_header_t)); +u64 sp_mem_arena_block_align(sp_mem_arena_block_t* block, u8 alignment) { + u8* buffer = sp_mem_arena_block_buffer(block); + u8* ptr = (u8*)sp_align_up(buffer + block->bytes_used, alignment); + return (u64)(ptr - buffer); } -void* sp_mem_arena_get_ptr(sp_mem_arena_header_t* header) { - return (void*)(header + 1); +bool sp_mem_arena_block_fits(sp_mem_arena_block_t* block, u64 offset, u64 size) { + return offset <= block->capacity && size <= block->capacity - offset; } -void* sp_mem_arena_align_block(sp_mem_arena_block_t* block, u8 alignment) { - block->bytes_used = sp_align_offset(block->bytes_used, alignment); - return block->buffer + block->bytes_used; -} - -sp_mem_arena_block_t* sp_mem_arena_get_block(sp_mem_arena_t* arena, u64 alloc_size) { +sp_mem_arena_block_t* sp_mem_arena_get_block(sp_mem_arena_t* arena, u64 size) { sp_mem_arena_block_t* block = arena->current; - u64 offset = sp_align_offset(block->bytes_used, arena->alignment); - - if (offset + alloc_size <= block->capacity) { + u64 offset = sp_mem_arena_block_align(block, arena->alignment); + if (sp_mem_arena_block_fits(block, offset, size)) { block->bytes_used = offset; return block; } - u64 new_capacity = sp_max(arena->block_size, alloc_size); - - if (block->next && block->next->capacity >= alloc_size) { - block->next->bytes_used = 0; - block = block->next; - } - else { - sp_mem_arena_block_t* new_block = sp_mem_arena_block_new(arena, new_capacity); - new_block->next = block->next; - block->next = new_block; - block = new_block; + if (block->next) { + sp_mem_arena_block_t* next = block->next; + next->bytes_used = 0; + u64 next_offset = sp_mem_arena_block_align(next, arena->alignment); + if (sp_mem_arena_block_fits(next, next_offset, size)) { + next->bytes_used = next_offset; + arena->current = next; + return next; + } } - arena->current = block; - return block; + if (arena->block_size < SP_MEM_ARENA_MAX_BLOCK_SIZE) { + arena->block_size = sp_min(arena->block_size * 2, (u64)SP_MEM_ARENA_MAX_BLOCK_SIZE); + } + u64 required = sizeof(sp_mem_arena_block_t) + arena->alignment + size; + sp_mem_arena_block_t* new_block = sp_mem_arena_block_new(arena, sp_max(arena->block_size, required)); + if (!new_block) return SP_NULLPTR; + new_block->next = block->next; + block->next = new_block; + new_block->bytes_used = sp_mem_arena_block_align(new_block, arena->alignment); + arena->current = new_block; + return new_block; } -void* sp_mem_arena_alloc_with_header(sp_mem_arena_t* arena, u64 size) { - u64 total = sizeof(sp_mem_arena_header_t) + size; +void* sp_mem_arena_alloc_size(sp_mem_arena_t* arena, u64 size) { + if (size > ((u64)-1) - SP_MEM_ARENA_MAX_BLOCK_SIZE) return SP_NULLPTR; - sp_mem_arena_block_t* block = sp_mem_arena_get_block(arena, total); - sp_mem_arena_header_t* header = (sp_mem_arena_header_t*)sp_mem_arena_align_block(block, arena->alignment); - header->size = size; + sp_mem_arena_block_t* block = sp_mem_arena_get_block(arena, size); + if (!block) return SP_NULLPTR; - void* ptr = sp_mem_arena_get_ptr(header); + void* ptr = sp_mem_arena_block_buffer(block) + block->bytes_used; + block->bytes_used += size; sp_mem_zero(ptr, size); - block->bytes_used += total; - return ptr; } -void* sp_mem_arena_alloc_no_header(sp_mem_arena_t* arena, u64 size) { - sp_mem_arena_block_t* block = sp_mem_arena_get_block(arena, size); - void* ptr = sp_mem_arena_align_block(block, arena->alignment); - sp_mem_zero(ptr, size); - block->bytes_used += size; - - return ptr; +bool sp_mem_arena_is_top(sp_mem_arena_t* arena, void* ptr, u64 size) { + sp_mem_arena_block_t* block = arena->current; + u8* buffer = sp_mem_arena_block_buffer(block); + return (u8*)ptr >= buffer && (u8*)ptr + size == buffer + block->bytes_used; } -void* sp_mem_arena_on_alloc(void* user_data, sp_mem_alloc_mode_t mode, u64 size, void* old_memory) { +void* sp_mem_arena_on_alloc(void* user_data, sp_mem_alloc_mode_t mode, u64 size, void* old_memory, u64 old_size) { sp_mem_arena_t* arena = (sp_mem_arena_t*)user_data; switch (mode) { case SP_ALLOCATOR_MODE_ALLOC: { - switch (arena->mode) { - case SP_MEM_ARENA_MODE_DEFAULT: { - return sp_mem_arena_alloc_with_header(arena, size); - } - case SP_MEM_ARENA_MODE_NO_REALLOC: { - return sp_mem_arena_alloc_no_header(arena, size); - } - } - SP_UNREACHABLE_RETURN(SP_NULLPTR); + return sp_mem_arena_alloc_size(arena, size); } case SP_ALLOCATOR_MODE_RESIZE: { - if (arena->mode == SP_MEM_ARENA_MODE_NO_REALLOC) return SP_NULLPTR; + if (!old_memory) return sp_mem_arena_alloc_size(arena, size); - void* ptr = sp_mem_arena_alloc_with_header(arena, size); - if (old_memory) { - sp_mem_arena_header_t* header = sp_mem_arena_get_header(old_memory); - sp_mem_move(ptr, old_memory, sp_min(header->size, size)); + sp_mem_arena_block_t* block = arena->current; + if (sp_mem_arena_is_top(arena, old_memory, old_size)) { + if (size <= old_size) { + block->bytes_used -= old_size - size; + return old_memory; + } + u64 grow = size - old_size; + if (grow <= block->capacity - block->bytes_used) { + sp_mem_zero(sp_mem_arena_block_buffer(block) + block->bytes_used, grow); + block->bytes_used += grow; + return old_memory; + } } - return ptr; + + if (size <= old_size) return old_memory; + + void* fresh = sp_mem_arena_alloc_size(arena, size); + if (!fresh) return SP_NULLPTR; + sp_mem_move(fresh, old_memory, old_size); + return fresh; } case SP_ALLOCATOR_MODE_FREE: { + if (old_memory && sp_mem_arena_is_top(arena, old_memory, old_size)) { + arena->current->bytes_used -= old_size; + } return SP_NULLPTR; } } @@ -8351,15 +8349,15 @@ void* sp_mem_arena_on_alloc(void* user_data, sp_mem_alloc_mode_t mode, u64 size, } void* sp_mem_arena_alloc(sp_mem_arena_t* arena, u64 size) { - return sp_mem_arena_on_alloc(arena, SP_ALLOCATOR_MODE_ALLOC, size, SP_NULLPTR); + return sp_mem_arena_on_alloc(arena, SP_ALLOCATOR_MODE_ALLOC, size, SP_NULLPTR, 0); } -void* sp_mem_arena_realloc(sp_mem_arena_t* arena, void* ptr, u64 size) { - return sp_mem_arena_on_alloc(arena, SP_ALLOCATOR_MODE_RESIZE, size, ptr); +void* sp_mem_arena_realloc(sp_mem_arena_t* arena, void* ptr, u64 old_size, u64 size) { + return sp_mem_arena_on_alloc(arena, SP_ALLOCATOR_MODE_RESIZE, size, ptr, old_size); } -void sp_mem_arena_free(sp_mem_arena_t* arena, void* ptr) { - sp_mem_arena_on_alloc(arena, SP_ALLOCATOR_MODE_FREE, 0, ptr); +void sp_mem_arena_free(sp_mem_arena_t* arena, void* ptr, u64 size) { + sp_mem_arena_on_alloc(arena, SP_ALLOCATOR_MODE_FREE, 0, ptr, size); } sp_mem_fixed_t sp_mem_fixed(void* buffer, u64 capacity) { @@ -8390,21 +8388,42 @@ u64 sp_mem_fixed_bytes_used(sp_mem_fixed_t* fixed) { return fixed->bytes_used; } -void* sp_mem_fixed_on_alloc(void* user_data, sp_mem_alloc_mode_t mode, u64 size, void* old_memory) { - (void)old_memory; +void* sp_mem_fixed_on_alloc(void* user_data, sp_mem_alloc_mode_t mode, u64 size, void* old_memory, u64 old_size) { sp_mem_fixed_t* fixed = (sp_mem_fixed_t*)user_data; switch (mode) { case SP_ALLOCATOR_MODE_ALLOC: { u8* ptr = (u8*)sp_align_up(fixed->buffer + fixed->bytes_used, fixed->alignment); u64 offset = (u64)(ptr - fixed->buffer); - if (offset + size > fixed->capacity) return SP_NULLPTR; + if (offset > fixed->capacity || size > fixed->capacity - offset) return SP_NULLPTR; fixed->bytes_used = offset + size; sp_mem_zero(ptr, size); return ptr; } - case SP_ALLOCATOR_MODE_RESIZE: + case SP_ALLOCATOR_MODE_RESIZE: { + if (!old_memory) return sp_mem_fixed_on_alloc(user_data, SP_ALLOCATOR_MODE_ALLOC, size, SP_NULLPTR, 0); + + bool is_top = (u8*)old_memory + old_size == fixed->buffer + fixed->bytes_used; + if (is_top) { + u64 offset = (u64)((u8*)old_memory - fixed->buffer); + if (size <= fixed->capacity - offset) { + if (size > old_size) sp_mem_zero((u8*)old_memory + old_size, size - old_size); + fixed->bytes_used = offset + size; + return old_memory; + } + } + + if (size <= old_size) return old_memory; + + void* fresh = sp_mem_fixed_on_alloc(user_data, SP_ALLOCATOR_MODE_ALLOC, size, SP_NULLPTR, 0); + if (!fresh) return SP_NULLPTR; + sp_mem_move(fresh, old_memory, old_size); + return fresh; + } case SP_ALLOCATOR_MODE_FREE: { + if (old_memory && (u8*)old_memory + old_size == fixed->buffer + fixed->bytes_used) { + fixed->bytes_used -= old_size; + } return SP_NULLPTR; } } @@ -8489,34 +8508,26 @@ void sp_mem_zero(void* buffer, u64 buffer_size) { } void* sp_mem_os_alloc(u64 size) { - sp_mem_os_header_t* h = (sp_mem_os_header_t*)sp_sys_alloc(size + sizeof(sp_mem_os_header_t)); - if (!h) return SP_NULLPTR; - h->size = size; - return h + 1; + return sp_sys_alloc(size); } -void sp_mem_os_free(void* ptr) { +void sp_mem_os_free(void* ptr, u64 size) { if (!ptr) return; - sp_mem_os_header_t* h = sp_mem_os_get_header(ptr); - sp_sys_free(h, h->size + sizeof(sp_mem_os_header_t)); + sp_sys_free(ptr, size); } -void* sp_mem_os_realloc(void* ptr, u64 size) { +void* sp_mem_os_realloc(void* ptr, u64 old_size, u64 size) { if (!ptr) return sp_mem_os_alloc(size); if (!size) { - sp_mem_os_free(ptr); + sp_mem_os_free(ptr, old_size); return SP_NULLPTR; } - - sp_mem_os_header_t* header = sp_mem_os_get_header(ptr); - if (header->size >= size) { - return ptr; - } + if (size == old_size) return ptr; void* mem = sp_mem_os_alloc(size); if (!mem) return SP_NULLPTR; - sp_mem_copy(mem, ptr, header->size); - sp_mem_os_free(ptr); + sp_mem_copy(mem, ptr, sp_min(old_size, size)); + sp_mem_os_free(ptr, old_size); return mem; } @@ -8890,7 +8901,7 @@ sp_wide_str_t sp_wtf8_to_wtf16(sp_mem_t mem, sp_str_t wtf8) { return (sp_wide_str_t) { .data = buf, .len = n }; error: - sp_free(mem, buf); + sp_free(mem, buf, (wtf8.len + 1) * sizeof(u16)); return result; } @@ -10314,7 +10325,7 @@ void sp_os_env_it_next(sp_os_env_it_t* it) { if (state->cursor[0] != L'\0') { sp_win32_env_it_set_current(it); } else { - sp_mem_os_free(state); + sp_mem_os_free(state, sizeof(sp_win32_env_it_t)); *it = sp_zero_s(sp_os_env_it_t); } } @@ -10355,7 +10366,7 @@ sp_os_env_it_t sp_os_env_it_begin() { os->it = sp_str_ht_it_init(os->env.vars); if (!sp_str_ht_it_valid(os->env.vars, os->it)) { - sp_mem_os_free(os); + sp_mem_os_free(os, sizeof(sp_linux_env_it_t)); return sp_zero_s(sp_os_env_it_t); } @@ -10379,7 +10390,7 @@ void sp_os_env_it_next(sp_os_env_it_t* it) { } else { it->key = sp_zero_s(sp_str_t); it->value = sp_zero_s(sp_str_t); - sp_mem_os_free(state); + sp_mem_os_free(state, sizeof(sp_linux_env_it_t)); it->os = SP_NULLPTR; } } @@ -10474,7 +10485,7 @@ void sp_sys_env(const c8** env, u32* len) { void sp_env_init(sp_mem_t mem, sp_env_t* env) { *env = sp_zero_s(sp_env_t); env->mem = mem; - env->arena = sp_mem_arena_new_ex(mem, 4096, SP_MEM_ARENA_MODE_NO_REALLOC, SP_MEM_ALIGNMENT); + env->arena = sp_mem_arena_new_ex(mem, 4096, SP_MEM_ALIGNMENT); sp_str_ht_init(mem, env->vars); } @@ -11208,13 +11219,13 @@ void sp_thread_init(sp_thread_t* thread, sp_thread_fn_t fn, void* userdata) { *thread = CreateThread(SP_NULLPTR, 0, sp_win32_thread_launch, launch, 0, SP_NULLPTR); if (!*thread) { sp_semaphore_destroy(&launch->semaphore); - sp_mem_os_free(launch); + sp_mem_os_free(launch, sizeof(sp_thread_launch_t)); return; } sp_semaphore_wait(&launch->semaphore); sp_semaphore_destroy(&launch->semaphore); - sp_mem_os_free(launch); + sp_mem_os_free(launch, sizeof(sp_thread_launch_t)); } s32 sp_thread_launch(void* args) { @@ -11861,8 +11872,8 @@ sp_ps_output_t sp_ps_output(sp_ps_t* ps) { } } - result.out = sp_io_dyn_mem_writer_as_str(&write.out); - result.err = sp_io_dyn_mem_writer_as_str(&write.err); + result.out = sp_io_dyn_mem_writer_take_str(&write.out); + result.err = sp_io_dyn_mem_writer_take_str(&write.err); result.status = sp_ps_wait(ps); return result; } @@ -11876,14 +11887,14 @@ bool sp_ps_kill(sp_ps_t* ps) { void sp_ps_free(sp_ps_t* ps) { if (!ps || !ps->os) return; - sp_free(ps->mem, ps->os); + sp_free(ps->mem, ps->os, sizeof(*ps->os)); ps->os = SP_NULLPTR; } void sp_ps_output_free(sp_mem_t mem, sp_ps_output_t* output) { if (!output) return; - sp_free(mem, (void*)output->out.data); - sp_free(mem, (void*)output->err.data); + sp_free(mem, (void*)output->out.data, output->out.len); + sp_free(mem, (void*)output->err.data, output->err.len); *output = sp_zero_s(sp_ps_output_t); } @@ -12493,8 +12504,8 @@ sp_ps_output_t sp_ps_output(sp_ps_t* ps) { ps->os->pid = SP_NULLPTR; } - result.out = sp_io_dyn_mem_writer_as_str(&out); - result.err = sp_io_dyn_mem_writer_as_str(&err); + result.out = sp_io_dyn_mem_writer_take_str(&out); + result.err = sp_io_dyn_mem_writer_take_str(&err); result.status = (sp_ps_status_t) { .state = SP_PS_STATE_DONE, .exit_code = process_done ? (s32)exit_code : -1, @@ -12523,14 +12534,14 @@ void sp_ps_free(sp_ps_t* ps) { CloseHandle(ps->os->pid); ps->os->pid = SP_NULLPTR; } - sp_free(ps->mem, ps->os); + sp_free(ps->mem, ps->os, sizeof(*ps->os)); ps->os = SP_NULLPTR; } void sp_ps_output_free(sp_mem_t mem, sp_ps_output_t* output) { if (!output) return; - sp_free(mem, (void*)output->out.data); - sp_free(mem, (void*)output->err.data); + sp_free(mem, (void*)output->out.data, output->out.len); + sp_free(mem, (void*)output->err.data, output->err.len); *output = sp_zero_s(sp_ps_output_t); } @@ -12793,12 +12804,12 @@ void sp_fmon_os_deinit(sp_fmon_t* monitor) { CloseHandle(info->overlapped.hEvent); } if (info->notify_information) { - sp_free(monitor->mem, info->notify_information); + sp_free(monitor->mem, info->notify_information, SP_FILE_MONITOR_BUFFER_SIZE); } } sp_da_free(os->dirs); sp_da_free(os->watch_files); - sp_free(monitor->mem, os); + sp_free(monitor->mem, os, sizeof(sp_fmon_os_t)); monitor->os = NULL; } @@ -13235,8 +13246,8 @@ void sp_fmon_os_init(sp_fmon_t* monitor) { os->queue = dispatch_queue_create("sp.fmon", DISPATCH_QUEUE_SERIAL); os->monitor = monitor; sp_mutex_init(&os->mutex, SP_MUTEX_PLAIN); - os->watch_arena = sp_mem_arena_new_ex(monitor->mem, SP_FMON_ARENA_SIZE, SP_MEM_ARENA_MODE_DEFAULT, SP_MEM_ALIGNMENT); - os->event_arena = sp_mem_arena_new_ex(monitor->mem, SP_FMON_ARENA_SIZE, SP_MEM_ARENA_MODE_DEFAULT, SP_MEM_ALIGNMENT); + os->watch_arena = sp_mem_arena_new_ex(monitor->mem, SP_FMON_ARENA_SIZE, SP_MEM_ALIGNMENT); + os->event_arena = sp_mem_arena_new_ex(monitor->mem, SP_FMON_ARENA_SIZE, SP_MEM_ALIGNMENT); os->mem.watch = sp_mem_arena_as_allocator(os->watch_arena); os->mem.event = sp_mem_arena_as_allocator(os->event_arena); sp_da_init(monitor->mem, os->watch_paths); @@ -13258,7 +13269,7 @@ void sp_fmon_os_deinit(sp_fmon_t* monitor) { sp_mutex_destroy(&os->mutex); sp_mem_arena_destroy(os->watch_arena); sp_mem_arena_destroy(os->event_arena); - sp_free(monitor->mem, os); + sp_free(monitor->mem, os, sizeof(sp_fmon_os_t)); monitor->os = SP_NULLPTR; } @@ -14350,7 +14361,7 @@ SP_API s32 sp_app_run(sp_app_config_t config) { s32 rc = (app->mode == SP_APP_MODE_FREE) ? sp_app_run_free(app) : sp_app_run_locked(app); - sp_mem_os_free(app); + sp_mem_os_free(app, sizeof(sp_app_t)); return rc; } @@ -14368,16 +14379,12 @@ SP_API s32 sp_app_run(sp_app_config_t config) { -sp_mem_os_header_t* sp_mem_os_get_header(void* ptr) { - return ((sp_mem_os_header_t*)ptr) - 1; -} - -void* sp_mem_os_on_alloc(void* user_data, sp_mem_alloc_mode_t mode, u64 size, void* ptr) { +void* sp_mem_os_on_alloc(void* user_data, sp_mem_alloc_mode_t mode, u64 size, void* ptr, u64 old_size) { (void)user_data; switch (mode) { case SP_ALLOCATOR_MODE_ALLOC: return sp_mem_os_alloc(size); - case SP_ALLOCATOR_MODE_RESIZE: return sp_mem_os_realloc(ptr, size); - case SP_ALLOCATOR_MODE_FREE: sp_mem_os_free(ptr); return SP_NULLPTR; + case SP_ALLOCATOR_MODE_RESIZE: return sp_mem_os_realloc(ptr, old_size, size); + case SP_ALLOCATOR_MODE_FREE: sp_mem_os_free(ptr, old_size); return SP_NULLPTR; default: return SP_NULLPTR; } } @@ -14618,7 +14625,8 @@ void* sp_mem_heap_realloc(sp_mem_heap_t* heap, void* ptr, u64 size) { return fresh; } -void* sp_mem_heap_on_alloc(void* user_data, sp_mem_alloc_mode_t mode, u64 size, void* ptr) { +void* sp_mem_heap_on_alloc(void* user_data, sp_mem_alloc_mode_t mode, u64 size, void* ptr, u64 old_size) { + sp_unused(old_size); sp_mem_heap_t* heap = (sp_mem_heap_t*)user_data; switch (mode) { case SP_ALLOCATOR_MODE_ALLOC: return sp_mem_heap_alloc(heap, size); @@ -14639,12 +14647,12 @@ void* sp_alloc(sp_mem_t allocator, u64 size) { return sp_mem_allocator_alloc(allocator, size); } -void* sp_realloc(sp_mem_t allocator, void* memory, u64 size) { - return sp_mem_allocator_realloc(allocator, memory, size); +void* sp_realloc(sp_mem_t allocator, void* memory, u64 old_size, u64 size) { + return sp_mem_allocator_realloc(allocator, memory, old_size, size); } -void sp_free(sp_mem_t allocator, void* memory) { - sp_mem_allocator_free(allocator, memory); +void sp_free(sp_mem_t allocator, void* memory, u64 size) { + sp_mem_allocator_free(allocator, memory, size); } sp_err_t sp_io_mem_writer_write(sp_io_writer_t* writer, const void* ptr, u64 size, u64* bytes_written) { @@ -14723,7 +14731,7 @@ sp_err_t sp_io_dyn_mem_writer_write(sp_io_writer_t* writer, const void* ptr, u64 while (new_capacity < required) { new_capacity *= 2; } - w->storage.data = (u8*)sp_mem_allocator_realloc(w->allocator, w->storage.data, new_capacity); + w->storage.data = (u8*)sp_mem_allocator_realloc(w->allocator, w->storage.data, w->storage.capacity, new_capacity); w->storage.capacity = new_capacity; } @@ -14781,7 +14789,7 @@ sp_err_t sp_io_dyn_mem_writer_close(sp_io_dyn_mem_writer_t* w) { sp_io_flush(&w->base); if (w->storage.data) { - sp_mem_allocator_free(w->allocator, w->storage.data); + sp_mem_allocator_free(w->allocator, w->storage.data, w->storage.capacity); w->storage = sp_zero_s(sp_mem_buffer_t); } return SP_OK; @@ -14802,6 +14810,15 @@ sp_str_t sp_io_dyn_mem_writer_as_str(sp_io_dyn_mem_writer_t* w) { return sp_mem_buffer_as_str(&w->storage); } +sp_str_t sp_io_dyn_mem_writer_take_str(sp_io_dyn_mem_writer_t* w) { + sp_str_t str = sp_mem_buffer_as_str(&w->storage); + if (w->storage.data && w->storage.capacity > str.len) { + str.data = (c8*)sp_mem_allocator_realloc(w->allocator, w->storage.data, w->storage.capacity, str.len); + } + w->storage = sp_zero_s(sp_mem_buffer_t); + return str; +} + const c8* sp_io_dyn_mem_writer_as_cstr(sp_io_dyn_mem_writer_t* w) { return sp_mem_buffer_as_cstr(&w->storage); } @@ -15604,12 +15621,15 @@ sp_err_t sp_io_read_file(sp_mem_t mem, sp_str_t path, sp_str_t* content) { buffer = sp_alloc_n(mem, c8, size); sp_try_goto(sp_io_read(&reader.base, buffer, size, &bytes_read), err, cleanup); + if (bytes_read < size) { + buffer = (c8*)sp_realloc(mem, buffer, size, bytes_read); + } content->data = buffer; content->len = (u32)bytes_read; buffer = SP_NULLPTR; cleanup: - if (buffer) sp_mem_allocator_free(mem, buffer); + if (buffer) sp_mem_allocator_free(mem, buffer, size); sp_io_file_reader_close(&reader); return err; } diff --git a/sp/sp_asset.h b/sp/sp_asset.h index c840a76..08cef60 100644 --- a/sp/sp_asset.h +++ b/sp/sp_asset.h @@ -74,7 +74,7 @@ struct sp_asset_registry { }; void sp_asset_registry_init(sp_asset_registry_t* r, sp_mem_t mem, sp_asset_registry_config_t config); -void* sp_asset_registry_on_alloc(void* ud, sp_mem_alloc_mode_t mode, u64 size, void* old); +void* sp_asset_registry_on_alloc(void* ud, sp_mem_alloc_mode_t mode, u64 size, void* old, u64 old_size); void sp_asset_registry_shutdown(sp_asset_registry_t* r); sp_asset_t* sp_asset_registry_import(sp_asset_registry_t* r, sp_asset_kind_t k, sp_str_t name, void* user_data); sp_asset_t* sp_asset_registry_add(sp_asset_registry_t* r, sp_asset_kind_t k, sp_str_t name, void* data); @@ -92,10 +92,10 @@ s32 sp_asset_registry_thread_fn(void* user_data); #endif #if defined(SP_ASSET_IMPLEMENTATION) -void* sp_asset_registry_on_alloc(void* ud, sp_mem_alloc_mode_t mode, u64 size, void* old) { +void* sp_asset_registry_on_alloc(void* ud, sp_mem_alloc_mode_t mode, u64 size, void* old, u64 old_size) { sp_asset_registry_t* r = (sp_asset_registry_t*)ud; sp_mutex_lock(&r->alloc_mutex); - void* result = sp_mem_arena_on_alloc(r->arena, mode, size, old); + void* result = sp_mem_arena_on_alloc(r->arena, mode, size, old, old_size); sp_mutex_unlock(&r->alloc_mutex); return result; } diff --git a/sp/sp_prompt.h b/sp/sp_prompt.h index ddfce79..68af15f 100644 --- a/sp/sp_prompt.h +++ b/sp/sp_prompt.h @@ -959,7 +959,7 @@ sp_prompt_ctx_t* sp_prompt_new(sp_mem_t mem) { sp_prompt_ctx_t* sp_prompt_begin(sp_mem_t mem) { sp_prompt_ctx_t* ctx = sp_prompt_new(mem); if (sp_prompt_begin_ex(ctx)) { - sp_free(mem, ctx); + sp_free(mem, ctx, sizeof(sp_prompt_ctx_t)); return SP_NULLPTR; } return ctx; @@ -1014,7 +1014,7 @@ void sp_prompt_ctx_init(sp_prompt_ctx_t* ctx, sp_mem_t mem, u32 cols, u32 rows) sp_da_init(ctx->mem, ctx->frames); sp_mutex_init(&ctx->channel.lock, SP_MUTEX_PLAIN); - ctx->channel.arena = sp_mem_arena_new_ex(mem, 4096, SP_MEM_ARENA_MODE_DEFAULT, SP_MEM_ALIGNMENT); + ctx->channel.arena = sp_mem_arena_new_ex(mem, 4096, SP_MEM_ALIGNMENT); // Write buffering is really important, because our rendering algorithm is extremely // naive. It's not much more than this: diff --git a/test/array.c b/test/array.c index c402122..103d230 100644 --- a/test/array.c +++ b/test/array.c @@ -150,7 +150,7 @@ UTEST_F(dyn_array, pointer_type) { } for (u64 i = 0; i < sp_da_size(arr); i++) { - sp_free(ut.mem, arr[i]); + sp_free(ut.mem, arr[i], sp_cstr_len(arr[i]) + 1); } sp_da_free(arr); diff --git a/test/bench/heap.c b/test/bench/heap.c index 7acf82f..798c7bf 100644 --- a/test/bench/heap.c +++ b/test/bench/heap.c @@ -105,14 +105,14 @@ static void bench_alloc_slot(const bench_workload_t* w, u32 slot) { } static void bench_free_slot(u32 slot) { - sp_free(state.mem, state.ptrs[slot]); + sp_free(state.mem, state.ptrs[slot], state.sizes[slot]); state.live_req -= state.sizes[slot]; state.ptrs[slot] = SP_NULLPTR; state.sizes[slot] = 0; } static void bench_realloc_slot(u32 slot, u64 size) { - state.ptrs[slot] = sp_realloc(state.mem, state.ptrs[slot], size); + state.ptrs[slot] = sp_realloc(state.mem, state.ptrs[slot], state.sizes[slot], size); SP_ASSERT(state.ptrs[slot]); bench_touch(state.ptrs[slot], size); state.live_req -= state.sizes[slot]; @@ -140,8 +140,9 @@ static bool bench_heap_sample(void* ctx, u64* used, u64* reserved) { } #if !defined(SP_FREESTANDING) -static void* bench_malloc_on_alloc(void* user_data, sp_mem_alloc_mode_t mode, u64 size, void* ptr) { +static void* bench_malloc_on_alloc(void* user_data, sp_mem_alloc_mode_t mode, u64 size, void* ptr, u64 old_size) { sp_unused(user_data); + sp_unused(old_size); switch (mode) { case SP_ALLOCATOR_MODE_ALLOC: return malloc(size); case SP_ALLOCATOR_MODE_RESIZE: return realloc(ptr, size); @@ -189,10 +190,10 @@ typedef struct { static bench_os_counters_t bench_os_counters = sp_zero; static u64 bench_os_reservation(u64 size) { - return sp_align_offset(size + sizeof(sp_mem_os_header_t), 4096); + return sp_align_offset(size, 4096); } -static void* bench_os_on_alloc(void* user_data, sp_mem_alloc_mode_t mode, u64 size, void* ptr) { +static void* bench_os_on_alloc(void* user_data, sp_mem_alloc_mode_t mode, u64 size, void* ptr, u64 old_size) { bench_os_counters_t* counters = (bench_os_counters_t*)user_data; switch (mode) { case SP_ALLOCATOR_MODE_ALLOC: { @@ -205,25 +206,22 @@ static void* bench_os_on_alloc(void* user_data, sp_mem_alloc_mode_t mode, u64 si return p; } case SP_ALLOCATOR_MODE_RESIZE: { - if (!ptr) return bench_os_on_alloc(user_data, SP_ALLOCATOR_MODE_ALLOC, size, SP_NULLPTR); - u64 old = sp_mem_os_get_header(ptr)->size; - void* p = sp_mem_os_realloc(ptr, size); + if (!ptr) return bench_os_on_alloc(user_data, SP_ALLOCATOR_MODE_ALLOC, size, SP_NULLPTR, 0); + void* p = sp_mem_os_realloc(ptr, old_size, size); if (p) { - u64 now = sp_mem_os_get_header(p)->size; - counters->used -= old; - counters->used += now; - counters->reserved -= bench_os_reservation(old); - counters->reserved += bench_os_reservation(now); + counters->used -= old_size; + counters->used += size; + counters->reserved -= bench_os_reservation(old_size); + counters->reserved += bench_os_reservation(size); counters->peak_reserved = sp_max(counters->peak_reserved, counters->reserved); } return p; } case SP_ALLOCATOR_MODE_FREE: { if (ptr) { - u64 old = sp_mem_os_get_header(ptr)->size; - counters->used -= old; - counters->reserved -= bench_os_reservation(old); - sp_mem_os_free(ptr); + counters->used -= old_size; + counters->reserved -= bench_os_reservation(old_size); + sp_mem_os_free(ptr, old_size); } return SP_NULLPTR; } diff --git a/test/bench/ubench.h b/test/bench/ubench.h index 956411b..41b4b29 100644 --- a/test/bench/ubench.h +++ b/test/bench/ubench.h @@ -551,7 +551,7 @@ void ubench_register_benchmark(sp_str_t name, ubench_body_t body, const ubench_f const ubench_size_t i = ubench_state.benchmarks_length++; ubench_state.benchmarks = sp_ptr_cast( ubench_benchmark_state_t*, - sp_realloc(ubench_state.mem, ubench_state.benchmarks, sizeof(ubench_benchmark_state_t) * ubench_state.benchmarks_length) + sp_realloc(ubench_state.mem, ubench_state.benchmarks, sizeof(ubench_benchmark_state_t) * i, sizeof(ubench_benchmark_state_t) * ubench_state.benchmarks_length) ); ubench_state.benchmarks[i].name = name; @@ -1190,7 +1190,7 @@ bench_store* bench_store_open(const c8 *path) { return s; error: - if (s) sp_mem_allocator_free(mem, s); + if (s) sp_mem_allocator_free(mem, s, sizeof(bench_store)); return SP_NULLPTR; } @@ -1200,7 +1200,7 @@ void bench_store_close(bench_store* s) { if (s->db) sqlite3_close(s->db); sp_mem_t mem = sp_mem_os_new(); - sp_mem_allocator_free(mem, s); + sp_mem_allocator_free(mem, s, sizeof(bench_store)); } s64 bench_store_begin_run(bench_store* s, const bench_machine_info* mi, const bench_run_info* ri) { @@ -1777,6 +1777,7 @@ s32 ubench_main(s32 argc, const c8 *const argv[]) { ubench_size_t *, sp_realloc(ubench_state.mem, sp_ptr_cast(void *, failed_benchmarks), + sizeof(ubench_size_t) * failed_benchmark_index, sizeof(ubench_size_t) * failed_benchmarks_length)); failed_benchmarks[failed_benchmark_index] = index; failed++; @@ -1857,8 +1858,8 @@ s32 ubench_main(s32 argc, const c8 *const argv[]) { } cleanup: - sp_free(ubench_state.mem, sp_ptr_cast(void *, failed_benchmarks)); - sp_free(ubench_state.mem, sp_ptr_cast(void *, ubench_state.benchmarks)); + sp_free(ubench_state.mem, sp_ptr_cast(void *, failed_benchmarks), sizeof(ubench_size_t) * failed_benchmarks_length); + sp_free(ubench_state.mem, sp_ptr_cast(void *, ubench_state.benchmarks), sizeof(ubench_benchmark_state_t) * ubench_state.benchmarks_length); #if defined(UBENCH_ENABLE_PERF_COUNTERS) && defined(SP_LINUX) ubench_perf_close(&perf); diff --git a/test/ht.c b/test/ht.c index 262bbdc..8b78f71 100644 --- a/test/ht.c +++ b/test/ht.c @@ -603,7 +603,7 @@ UTEST_F(siphash, collision_resistance) { EXPECT_EQ(collisions, 0); - sp_free(ut.mem, hashes); + sp_free(ut.mem, hashes, count * sizeof(u64)); } UTEST_F(sp_ht, hash_table_with_dyn_array_values) { diff --git a/test/leak.c b/test/leak.c index 38a74ae..06bfc8e 100644 --- a/test/leak.c +++ b/test/leak.c @@ -38,7 +38,7 @@ UTEST(tracking, alloc_free_balance) { EXPECT_EQ(t.live_count, 1u); EXPECT_EQ(t.live_bytes, 64u); - sp_free(mem, p); + sp_free(mem, p, 64); EXPECT_EQ(t.live_count, 0u); EXPECT_EQ(t.live_bytes, 0u); EXPECT_EQ(t.double_frees, 0u); @@ -55,7 +55,7 @@ UTEST(tracking, detects_leak) { sp_alloc(mem, 16); sp_alloc(mem, 32); void* freed = sp_alloc(mem, 8); - sp_free(mem, freed); + sp_free(mem, freed, 8); EXPECT_EQ(t.live_count, 2u); EXPECT_EQ(t.live_bytes, 48u); @@ -69,9 +69,9 @@ UTEST(tracking, detects_double_free) { sp_mem_t mem = sp_mem_tracking_as_allocator(&t); void* p = sp_alloc(mem, 64); - sp_free(mem, p); - sp_free(mem, p); - sp_free(mem, p); + sp_free(mem, p, 64); + sp_free(mem, p, 64); + sp_free(mem, p, 64); EXPECT_EQ(t.double_frees, 2u); EXPECT_EQ(t.live_count, 0u); @@ -90,7 +90,7 @@ UTEST(tracking, detects_wild_free) { // large enough for the back-step, and the bytes there won't match either // sentinel (we zero-init the buffer). static u8 buf[256] = {0}; - sp_free(mem, &buf[200]); + sp_free(mem, &buf[200], 8); EXPECT_EQ(t.wild_frees, 1u); EXPECT_EQ(t.double_frees, 0u); @@ -104,7 +104,7 @@ UTEST(tracking, free_null_is_noop) { sp_mem_tracking_init(&t); sp_mem_t mem = sp_mem_tracking_as_allocator(&t); - sp_free(mem, SP_NULLPTR); + sp_free(mem, SP_NULLPTR, 0); EXPECT_EQ(t.double_frees, 0u); EXPECT_EQ(t.wild_frees, 0u); @@ -121,14 +121,14 @@ UTEST(tracking, realloc_grows_and_preserves) { u8* p = sp_alloc_n(mem, u8, 4); sp_for(i, 4) p[i] = (u8)(i + 1); - u8* g = sp_void_cast(g, sp_realloc(mem, p, 64)); + u8* g = sp_void_cast(g, sp_realloc(mem, p, 4, 64)); EXPECT_NE(g, SP_NULLPTR); sp_for(i, 4) EXPECT_EQ(g[i], (u8)(i + 1)); EXPECT_EQ(t.live_count, 1u); EXPECT_EQ(t.live_bytes, 64u); - sp_free(mem, g); + sp_free(mem, g, 64); EXPECT_EQ(t.live_count, 0u); sp_mem_tracking_deinit(&t); @@ -139,12 +139,12 @@ UTEST(tracking, realloc_null_is_alloc) { sp_mem_tracking_init(&t); sp_mem_t mem = sp_mem_tracking_as_allocator(&t); - void* p = sp_realloc(mem, SP_NULLPTR, 32); + void* p = sp_realloc(mem, SP_NULLPTR, 0, 32); EXPECT_NE(p, SP_NULLPTR); EXPECT_EQ(t.live_count, 1u); EXPECT_EQ(t.live_bytes, 32u); - sp_free(mem, p); + sp_free(mem, p, 32); sp_mem_tracking_deinit(&t); } @@ -154,7 +154,7 @@ UTEST(tracking, realloc_zero_is_free) { sp_mem_t mem = sp_mem_tracking_as_allocator(&t); void* p = sp_alloc(mem, 32); - void* r = sp_realloc(mem, p, 0); + void* r = sp_realloc(mem, p, 32, 0); EXPECT_EQ(r, SP_NULLPTR); EXPECT_EQ(t.live_count, 0u); EXPECT_EQ(t.live_bytes, 0u); @@ -200,11 +200,11 @@ UTEST_F(leak, multiple_allocs_independent) { EXPECT_EQ(ut.tracker.live_count, 3u); EXPECT_EQ(ut.tracker.live_bytes, 56u); - sp_free(ut.mem, b); + sp_free(ut.mem, b, 16); EXPECT_EQ(ut.tracker.live_count, 2u); EXPECT_EQ(ut.tracker.live_bytes, 40u); - sp_free(ut.mem, a); - sp_free(ut.mem, c); + sp_free(ut.mem, a, 8); + sp_free(ut.mem, c, 32); EXPECT_EQ(ut.tracker.live_count, 0u); } diff --git a/test/mem/arena.c b/test/mem/arena.c index bb99e5c..39cffdc 100644 --- a/test/mem/arena.c +++ b/test/mem/arena.c @@ -29,11 +29,11 @@ UTEST_F(mem, arena_padding_mixed_sizes) { } UTEST_F(mem, arena_basic_alloc) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ARENA_MODE_DEFAULT, SP_MEM_ALIGNMENT); + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ALIGNMENT); sp_mem_t allocator = sp_mem_arena_as_allocator(arena); EXPECT_EQ(sp_mem_arena_bytes_used(arena), 0u); - EXPECT_EQ(sp_mem_arena_capacity(arena), 256u); + EXPECT_EQ(sp_mem_arena_capacity(arena), 256u - sizeof(sp_mem_arena_block_t)); u8* first = sp_void_cast(first, sp_mem_allocator_alloc(allocator, 16)); EXPECT_ALIGNED(first); @@ -43,7 +43,7 @@ UTEST_F(mem, arena_basic_alloc) { } UTEST_F(mem, arena_allocations_are_zeroed) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ARENA_MODE_DEFAULT, SP_MEM_ALIGNMENT); + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ALIGNMENT); sp_mem_t allocator = sp_mem_arena_as_allocator(arena); u8* first = sp_void_cast(first, sp_mem_allocator_alloc(allocator, 64)); @@ -53,8 +53,24 @@ UTEST_F(mem, arena_allocations_are_zeroed) { sp_mem_arena_destroy(arena); } +UTEST_F(mem, arena_packed_no_header_overhead) { + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ALIGNMENT); + sp_mem_t allocator = sp_mem_arena_as_allocator(arena); + + u8* first = sp_void_cast(first, sp_mem_allocator_alloc(allocator, 16)); + EXPECT_ALIGNED(first); + EXPECT_EQ(sp_mem_arena_bytes_used(arena), 16u); + + u8* second = sp_void_cast(second, sp_mem_allocator_alloc(allocator, 32)); + EXPECT_ALIGNED(second); + EXPECT_EQ(second, first + 16); + EXPECT_EQ(sp_mem_arena_bytes_used(arena), 48u); + + sp_mem_arena_destroy(arena); +} + UTEST_F(mem, arena_pop_resets_bytes_used) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ARENA_MODE_DEFAULT, SP_MEM_ALIGNMENT); + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ALIGNMENT); sp_mem_t allocator = sp_mem_arena_as_allocator(arena); sp_mem_arena_marker_t marker = sp_mem_arena_mark(arena); @@ -70,7 +86,7 @@ UTEST_F(mem, arena_pop_resets_bytes_used) { } UTEST_F(mem, arena_block_chaining) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 64, SP_MEM_ARENA_MODE_DEFAULT, SP_MEM_ALIGNMENT); + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 64, SP_MEM_ALIGNMENT); sp_mem_t allocator = sp_mem_arena_as_allocator(arena); u8* a = sp_void_cast(a, sp_mem_allocator_alloc(allocator, 32)); @@ -89,13 +105,13 @@ UTEST_F(mem, arena_block_chaining) { EXPECT_EQ(b[0], 0xBB); EXPECT_EQ(c[0], 0xCC); - EXPECT_GT(sp_mem_arena_capacity(arena), 64u); + EXPECT_GT(sp_mem_arena_capacity(arena), 64u - sizeof(sp_mem_arena_block_t)); sp_mem_arena_destroy(arena); } UTEST_F(mem, arena_pop_across_blocks) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 64, SP_MEM_ARENA_MODE_DEFAULT, SP_MEM_ALIGNMENT); + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 64, SP_MEM_ALIGNMENT); sp_mem_t allocator = sp_mem_arena_as_allocator(arena); sp_mem_arena_marker_t marker = sp_mem_arena_mark(arena); @@ -118,15 +134,36 @@ UTEST_F(mem, arena_pop_across_blocks) { sp_mem_arena_destroy(arena); } -UTEST_F(mem, arena_realloc_copies_data) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ARENA_MODE_DEFAULT, SP_MEM_ALIGNMENT); +UTEST_F(mem, arena_realloc_extends_top_in_place) { + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ALIGNMENT); + sp_mem_t allocator = sp_mem_arena_as_allocator(arena); + + u8* first = sp_void_cast(first, sp_mem_allocator_alloc(allocator, 16)); + sp_mem_fill_u8(first, 16, 0xAA); + + u8* resized = sp_void_cast(resized, sp_mem_allocator_realloc(allocator, first, 16, 32)); + + EXPECT_EQ(resized, first); + EXPECT_EQ(resized[0], 0xAA); + EXPECT_EQ(resized[15], 0xAA); + EXPECT_EQ(resized[16], 0x00); + EXPECT_EQ(resized[31], 0x00); + EXPECT_EQ(sp_mem_arena_bytes_used(arena), 32u); + + sp_mem_arena_destroy(arena); +} + +UTEST_F(mem, arena_realloc_copies_when_not_top) { + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ALIGNMENT); sp_mem_t allocator = sp_mem_arena_as_allocator(arena); u8* first = sp_void_cast(first, sp_mem_allocator_alloc(allocator, 16)); sp_mem_fill_u8(first, 16, 0xAA); + sp_mem_allocator_alloc(allocator, 16); - u8* resized = sp_void_cast(resized, sp_mem_allocator_realloc(allocator, first, 32)); + u8* resized = sp_void_cast(resized, sp_mem_allocator_realloc(allocator, first, 16, 32)); + EXPECT_NE(resized, first); EXPECT_EQ(resized[0], 0xAA); EXPECT_EQ(resized[15], 0xAA); EXPECT_EQ(resized[16], 0x00); @@ -135,8 +172,40 @@ UTEST_F(mem, arena_realloc_copies_data) { sp_mem_arena_destroy(arena); } +UTEST_F(mem, arena_realloc_shrink_returns_same_pointer) { + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ALIGNMENT); + sp_mem_t allocator = sp_mem_arena_as_allocator(arena); + + u8* first = sp_void_cast(first, sp_mem_allocator_alloc(allocator, 32)); + sp_mem_fill_u8(first, 32, 0xAA); + + u8* resized = sp_void_cast(resized, sp_mem_allocator_realloc(allocator, first, 32, 16)); + + EXPECT_EQ(resized, first); + EXPECT_EQ(sp_mem_arena_bytes_used(arena), 16u); + + sp_mem_arena_destroy(arena); +} + +UTEST_F(mem, arena_free_reclaims_top) { + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ALIGNMENT); + sp_mem_t allocator = sp_mem_arena_as_allocator(arena); + + u8* first = sp_void_cast(first, sp_mem_allocator_alloc(allocator, 32)); + u8* second = sp_void_cast(second, sp_mem_allocator_alloc(allocator, 32)); + EXPECT_EQ(sp_mem_arena_bytes_used(arena), 64u); + + sp_mem_allocator_free(allocator, first, 32); + EXPECT_EQ(sp_mem_arena_bytes_used(arena), 64u); + + sp_mem_allocator_free(allocator, second, 32); + EXPECT_EQ(sp_mem_arena_bytes_used(arena), 32u); + + sp_mem_arena_destroy(arena); +} + UTEST_F(mem, arena_clear_resets_all_blocks) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 64, SP_MEM_ARENA_MODE_DEFAULT, SP_MEM_ALIGNMENT); + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 64, SP_MEM_ALIGNMENT); sp_mem_t allocator = sp_mem_arena_as_allocator(arena); sp_mem_allocator_alloc(allocator, 32); @@ -153,7 +222,7 @@ UTEST_F(mem, arena_clear_resets_all_blocks) { } UTEST_F(mem, arena_block_reuse_after_pop) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 64, SP_MEM_ARENA_MODE_DEFAULT, SP_MEM_ALIGNMENT); + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 64, SP_MEM_ALIGNMENT); sp_mem_t allocator = sp_mem_arena_as_allocator(arena); sp_mem_arena_marker_t marker = sp_mem_arena_mark(arena); @@ -175,124 +244,66 @@ UTEST_F(mem, arena_block_reuse_after_pop) { sp_mem_arena_destroy(arena); } -UTEST_F(mem, arena_reuse_logic_check) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 64, SP_MEM_ARENA_MODE_DEFAULT, SP_MEM_ALIGNMENT); +UTEST_F(mem, arena_block_reuse_after_clear) { + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 64, SP_MEM_ALIGNMENT); sp_mem_t allocator = sp_mem_arena_as_allocator(arena); sp_mem_allocator_alloc(allocator, 40); - sp_mem_allocator_alloc(allocator, 40); u64 cap_initial = sp_mem_arena_capacity(arena); - EXPECT_EQ(cap_initial, 128u); sp_mem_arena_clear(arena); sp_mem_allocator_alloc(allocator, 40); - sp_mem_allocator_alloc(allocator, 40); u64 cap_after = sp_mem_arena_capacity(arena); - EXPECT_EQ(cap_after, 128u); + EXPECT_EQ(cap_after, cap_initial); sp_mem_arena_destroy(arena); } -UTEST_F(mem, arena_wrappers) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 64, SP_MEM_ARENA_MODE_DEFAULT, SP_MEM_ALIGNMENT); - EXPECT_NE(sp_mem_arena_alloc(arena, 8), SP_NULLPTR); - void* ptr = sp_mem_arena_alloc(arena, 8); - EXPECT_NE(sp_mem_arena_realloc(arena, ptr, 72), SP_NULLPTR); - sp_mem_arena_free(arena, ptr); -} - -UTEST_F(mem, arena_no_realloc_basic) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ARENA_MODE_NO_REALLOC, 0); +UTEST_F(mem, arena_block_size_grows_geometrically) { + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 64, SP_MEM_ALIGNMENT); sp_mem_t allocator = sp_mem_arena_as_allocator(arena); - EXPECT_EQ(sp_mem_arena_bytes_used(arena), 0u); + sp_for(it, 64) { + sp_mem_allocator_alloc(allocator, 32); + } - u8* first = sp_void_cast(first, sp_mem_allocator_alloc(allocator, 16)); - EXPECT_ALIGNED(first); - EXPECT_EQ(sp_mem_arena_bytes_used(arena), 16u); + u32 num_blocks = 0; + for (sp_mem_arena_block_t* block = arena->head; block; block = block->next) { + num_blocks++; + } - u8* second = sp_void_cast(second, sp_mem_allocator_alloc(allocator, 32)); - EXPECT_ALIGNED(second); - EXPECT_EQ(sp_mem_arena_bytes_used(arena), 48u); + EXPECT_LT(num_blocks, 16u); + EXPECT_GE(sp_mem_arena_capacity(arena), 64u * 32u); sp_mem_arena_destroy(arena); } -UTEST_F(mem, arena_no_realloc_no_header_overhead) { - sp_mem_arena_t* no_realloc = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ARENA_MODE_NO_REALLOC, 0); - sp_mem_arena_t* normal = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ARENA_MODE_DEFAULT, 0); - - sp_mem_arena_alloc(no_realloc, 16); - sp_mem_arena_alloc(normal, 16); - - u64 no_realloc_used = sp_mem_arena_bytes_used(no_realloc); - u64 normal_used = sp_mem_arena_bytes_used(normal); - - EXPECT_LT(no_realloc_used, normal_used); - - sp_mem_arena_destroy(no_realloc); - sp_mem_arena_destroy(normal); -} - -UTEST_F(mem, arena_no_realloc_allocations_zeroed) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ARENA_MODE_NO_REALLOC, 0); - sp_mem_t allocator = sp_mem_arena_as_allocator(arena); - - u8* buf = sp_void_cast(buf, sp_mem_allocator_alloc(allocator, 64)); - EXPECT_EQ(buf[0], 0x00); - EXPECT_EQ(buf[63], 0x00); - - sp_mem_arena_destroy(arena); -} - -UTEST_F(mem, arena_no_realloc_block_chaining) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 64, SP_MEM_ARENA_MODE_NO_REALLOC, 0); - sp_mem_t allocator = sp_mem_arena_as_allocator(arena); - - u8* a = sp_void_cast(a, sp_mem_allocator_alloc(allocator, 32)); - u8* b = sp_void_cast(b, sp_mem_allocator_alloc(allocator, 32)); - u8* c = sp_void_cast(c, sp_mem_allocator_alloc(allocator, 32)); - - EXPECT_ALIGNED(a); - EXPECT_ALIGNED(b); - EXPECT_ALIGNED(c); - - sp_mem_fill_u8(a, 32, 0xAA); - sp_mem_fill_u8(b, 32, 0xBB); - sp_mem_fill_u8(c, 32, 0xCC); - - EXPECT_EQ(a[0], 0xAA); - EXPECT_EQ(b[0], 0xBB); - EXPECT_EQ(c[0], 0xCC); - - EXPECT_GT(sp_mem_arena_capacity(arena), 64u); - +UTEST_F(mem, arena_wrappers) { + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 64, SP_MEM_ALIGNMENT); + EXPECT_NE(sp_mem_arena_alloc(arena, 8), SP_NULLPTR); + void* ptr = sp_mem_arena_alloc(arena, 8); + EXPECT_NE(sp_mem_arena_realloc(arena, ptr, 8, 72), SP_NULLPTR); + sp_mem_arena_free(arena, ptr, 8); sp_mem_arena_destroy(arena); } -UTEST_F(mem, arena_no_realloc_mark_pop) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ARENA_MODE_NO_REALLOC, 0); - sp_mem_t allocator = sp_mem_arena_as_allocator(arena); - - sp_mem_arena_marker_t marker = sp_mem_arena_mark(arena); - - sp_mem_allocator_alloc(allocator, 64); - EXPECT_EQ(sp_mem_arena_bytes_used(arena), 64u); +UTEST_F(mem, arena_huge_alloc_returns_null) { + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 64, SP_MEM_ALIGNMENT); - sp_mem_arena_pop(marker); + EXPECT_EQ(sp_mem_arena_alloc(arena, (u64)-8), SP_NULLPTR); EXPECT_EQ(sp_mem_arena_bytes_used(arena), 0u); sp_mem_arena_destroy(arena); } UTEST_F(mem, arena_unaligned_basic) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ARENA_MODE_NO_REALLOC, 1); + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, 1); sp_mem_t allocator = sp_mem_arena_as_allocator(arena); EXPECT_EQ(sp_mem_arena_bytes_used(arena), 0u); @@ -308,7 +319,7 @@ UTEST_F(mem, arena_unaligned_basic) { } UTEST_F(mem, arena_unaligned_no_padding) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ARENA_MODE_NO_REALLOC, 1); + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, 1); sp_mem_t allocator = sp_mem_arena_as_allocator(arena); u8* a = sp_void_cast(a, sp_mem_allocator_alloc(allocator, 3)); @@ -323,7 +334,7 @@ UTEST_F(mem, arena_unaligned_no_padding) { } UTEST_F(mem, arena_unaligned_allocations_zeroed) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ARENA_MODE_NO_REALLOC, 1); + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, 1); sp_mem_t allocator = sp_mem_arena_as_allocator(arena); u8* buf = sp_void_cast(buf, sp_mem_allocator_alloc(allocator, 64)); @@ -334,7 +345,7 @@ UTEST_F(mem, arena_unaligned_allocations_zeroed) { } UTEST_F(mem, arena_unaligned_block_chaining) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 64, SP_MEM_ARENA_MODE_NO_REALLOC, 1); + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 64, 1); sp_mem_t allocator = sp_mem_arena_as_allocator(arena); u8* a = sp_void_cast(a, sp_mem_allocator_alloc(allocator, 60)); @@ -346,13 +357,13 @@ UTEST_F(mem, arena_unaligned_block_chaining) { EXPECT_EQ(a[0], 0xAA); EXPECT_EQ(b[0], 0xBB); - EXPECT_GT(sp_mem_arena_capacity(arena), 64u); + EXPECT_GT(sp_mem_arena_capacity(arena), 64u - sizeof(sp_mem_arena_block_t)); sp_mem_arena_destroy(arena); } UTEST_F(mem, arena_custom_alignment_4) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ARENA_MODE_NO_REALLOC, 4); + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, 4); sp_mem_t allocator = sp_mem_arena_as_allocator(arena); u8* a = sp_void_cast(a, sp_mem_allocator_alloc(allocator, 1)); @@ -370,7 +381,7 @@ UTEST_F(mem, arena_custom_alignment_4) { } UTEST_F(mem, arena_custom_alignment_8) { - sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, SP_MEM_ARENA_MODE_NO_REALLOC, 8); + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, 8); sp_mem_t allocator = sp_mem_arena_as_allocator(arena); u8* a = sp_void_cast(a, sp_mem_allocator_alloc(allocator, 3)); @@ -383,3 +394,29 @@ UTEST_F(mem, arena_custom_alignment_8) { sp_mem_arena_destroy(arena); } + +UTEST_F(mem, arena_custom_alignment_64) { + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 4096, 64); + sp_mem_t allocator = sp_mem_arena_as_allocator(arena); + + sp_for(it, 8) { + u8* p = sp_void_cast(p, sp_mem_allocator_alloc(allocator, 24)); + EXPECT_EQ((uintptr_t)p % 64, 0u); + } + + sp_mem_arena_destroy(arena); +} + +UTEST_F(mem, arena_custom_alignment_64_across_blocks) { + sp_mem_arena_t* arena = sp_mem_arena_new_ex(sp_mem_os_new(), 256, 64); + sp_mem_t allocator = sp_mem_arena_as_allocator(arena); + + sp_for(it, 8) { + u8* p = sp_void_cast(p, sp_mem_allocator_alloc(allocator, 100)); + EXPECT_EQ((uintptr_t)p % 64, 0u); + } + + EXPECT_GT(sp_mem_arena_capacity(arena), 256u); + + sp_mem_arena_destroy(arena); +} diff --git a/test/mem/builtin.c b/test/mem/builtin.c index a18e276..16a3384 100644 --- a/test/mem/builtin.c +++ b/test/mem/builtin.c @@ -341,9 +341,10 @@ UTEST_F(mem, zero_large) { run_mem_zero_test(utest_result, (mem_zero_test_t){ .buffer_size = 400 }); } -static void* mock_alloc_record_size(void* user_data, sp_mem_alloc_mode_t mode, u64 size, void* ptr) { +static void* mock_alloc_record_size(void* user_data, sp_mem_alloc_mode_t mode, u64 size, void* ptr, u64 old_size) { (void)mode; (void)ptr; + (void)old_size; *(u64*)user_data = size; return SP_NULLPTR; } @@ -361,15 +362,14 @@ UTEST_F(mem, alloc_preserves_u64_size) { EXPECT_EQ(recorded_size, requested); } -UTEST_F(mem, libc_metadata_stores_u64_size) { - sp_mem_t libc = sp_mem_os_new(); +UTEST_F(mem, os_alloc_roundtrip) { + sp_mem_t os = sp_mem_os_new(); u64 size = 64; - void* ptr = sp_mem_allocator_alloc(libc, size); + u8* ptr = sp_void_cast(ptr, sp_mem_allocator_alloc(os, size)); ASSERT_TRUE(ptr); + EXPECT_EQ(ptr[0], 0x00); + EXPECT_EQ(ptr[63], 0x00); - sp_mem_os_header_t* meta = sp_mem_os_get_header(ptr); - EXPECT_EQ(meta->size, size); - - sp_mem_allocator_free(libc, ptr); + sp_mem_allocator_free(os, ptr, size); } diff --git a/test/mem/fixed.c b/test/mem/fixed.c index f84565c..faf0d9b 100644 --- a/test/mem/fixed.c +++ b/test/mem/fixed.c @@ -123,17 +123,20 @@ UTEST_F(mem, fixed_overflow_returns_null) { EXPECT_EQ(overflow, SP_NULLPTR); } -UTEST_F(mem, fixed_free_is_noop) { +UTEST_F(mem, fixed_free_reclaims_top) { u8 storage [256]; sp_mem_fixed_t fixed = sp_mem_fixed(storage, sizeof(storage)); sp_mem_t allocator = sp_mem_fixed_as_allocator(&fixed); u8* first = sp_void_cast(first, sp_mem_allocator_alloc(allocator, 32)); + u8* second = sp_void_cast(second, sp_mem_allocator_alloc(allocator, 32)); u64 used_before = sp_mem_fixed_bytes_used(&fixed); - sp_mem_allocator_free(allocator, first); - + sp_mem_allocator_free(allocator, first, 32); EXPECT_EQ(sp_mem_fixed_bytes_used(&fixed), used_before); + + sp_mem_allocator_free(allocator, second, 32); + EXPECT_LT(sp_mem_fixed_bytes_used(&fixed), used_before); } UTEST_F(mem, fixed_unaligned_basic) { @@ -207,12 +210,42 @@ UTEST_F(mem, fixed_unaligned_base_returns_aligned_ptrs) { EXPECT_GE((uintptr_t)b, (uintptr_t)(a + 8)); } -UTEST_F(mem, fixed_resize_returns_null) { +UTEST_F(mem, fixed_resize_extends_top_in_place) { + SP_ALIGNED u8 storage [256]; + sp_mem_fixed_t fixed = sp_mem_fixed(storage, sizeof(storage)); + sp_mem_t allocator = sp_mem_fixed_as_allocator(&fixed); + + u8* first = sp_void_cast(first, sp_mem_allocator_alloc(allocator, 16)); + sp_mem_fill_u8(first, 16, 0xAA); + u8* resized = sp_void_cast(resized, sp_mem_allocator_realloc(allocator, first, 16, 32)); + EXPECT_EQ(resized, first); + EXPECT_EQ(resized[15], 0xAA); + EXPECT_EQ(resized[16], 0x00); + EXPECT_EQ(sp_mem_fixed_bytes_used(&fixed), 32u); +} + +UTEST_F(mem, fixed_resize_copies_when_not_top) { u8 storage [256]; sp_mem_fixed_t fixed = sp_mem_fixed(storage, sizeof(storage)); sp_mem_t allocator = sp_mem_fixed_as_allocator(&fixed); u8* first = sp_void_cast(first, sp_mem_allocator_alloc(allocator, 16)); - void* resized = sp_mem_allocator_realloc(allocator, first, 32); + sp_mem_fill_u8(first, 16, 0xAA); + sp_mem_allocator_alloc(allocator, 16); + + u8* resized = sp_void_cast(resized, sp_mem_allocator_realloc(allocator, first, 16, 32)); + EXPECT_NE(resized, first); + EXPECT_EQ(resized[0], 0xAA); + EXPECT_EQ(resized[15], 0xAA); + EXPECT_EQ(resized[16], 0x00); +} + +UTEST_F(mem, fixed_resize_fails_when_full) { + u8 storage [32]; + sp_mem_fixed_t fixed = sp_mem_fixed(storage, sizeof(storage)); + sp_mem_t allocator = sp_mem_fixed_as_allocator(&fixed); + + u8* first = sp_void_cast(first, sp_mem_allocator_alloc(allocator, 16)); + void* resized = sp_mem_allocator_realloc(allocator, first, 16, 256); EXPECT_EQ(resized, SP_NULLPTR); } diff --git a/test/mem/heap.c b/test/mem/heap.c index 735b05a..ab7f69d 100644 --- a/test/mem/heap.c +++ b/test/mem/heap.c @@ -688,9 +688,9 @@ UTEST_F(mem, heap_as_allocator_routes_through_sp_alloc) { EXPECT_NE(p, SP_NULLPTR); EXPECT_EQ((uintptr_t)p & (SP_MEM_ALIGNMENT - 1), 0u); - u8* q = sp_ptr_cast(u8*, sp_realloc(mem, p, 128)); + u8* q = sp_ptr_cast(u8*, sp_realloc(mem, p, 64, 128)); EXPECT_NE(q, SP_NULLPTR); - sp_free(mem, q); + sp_free(mem, q, 128); sp_mem_heap_destroy(heap); } diff --git a/test/prompt.c b/test/prompt.c index 2fb7ae9..d04f153 100644 --- a/test/prompt.c +++ b/test/prompt.c @@ -2375,7 +2375,7 @@ UTEST_F(prompt, prompt_end_frees_channel) { sp_prompt_send_status(ctx, "halfway"); sp_prompt_complete(ctx); sp_prompt_end(ctx); - sp_free(ut.mem.tracking, ctx); + sp_free(ut.mem.tracking, ctx, sizeof(sp_prompt_ctx_t)); } typedef struct { diff --git a/test/tools/stress.c b/test/tools/stress.c index 568de61..f8d13ff 100644 --- a/test/tools/stress.c +++ b/test/tools/stress.c @@ -320,14 +320,14 @@ UTEST(stress, sp_context) { u8* ptr = sp_alloc(s.mem, 16); sp_mem_fill_u8(ptr, 16, 0x11); - ptr = sp_mem_allocator_realloc(s.mem, ptr, 32); + ptr = sp_mem_allocator_realloc(s.mem, ptr, 16, 32); sp_for(it, 16) EXPECT_EQ(ptr[it], 0x11); sp_mem_fill_u8(ptr + 16, 16, 0x22); - ptr = sp_mem_allocator_realloc(s.mem, ptr, 8); + ptr = sp_mem_allocator_realloc(s.mem, ptr, 32, 8); sp_for(it, 8) ASSERT_EQ(ptr[it], 0x11); - ptr = sp_mem_allocator_realloc(s.mem, ptr, 8000); + ptr = sp_mem_allocator_realloc(s.mem, ptr, 8, 8000); sp_for(it, 8) ASSERT_EQ(ptr[it], 0x11); sp_mem_end_scratch(s); @@ -508,7 +508,7 @@ UTEST(stress, fmon) { // Cleanup sp_fmon_deinit(monitor); - sp_free(sp_mem_os_new(), monitor); + sp_free(sp_mem_os_new(), monitor, sizeof(sp_fmon_t)); sp_da_free(files); sp_da_free(dirs); sp_test_file_manager_cleanup(&file_manager); diff --git a/test/tools/test.h b/test/tools/test.h index 0561e0d..2a1686c 100644 --- a/test/tools/test.h +++ b/test/tools/test.h @@ -129,6 +129,7 @@ typedef struct sp_mem_tracking_t { u32 live_count; u32 double_frees; u32 wild_frees; + u32 bad_sizes; u32 next_id; } sp_mem_tracking_t; @@ -137,7 +138,7 @@ void sp_mem_tracking_init_ex(sp_mem_tracking_t* t, sp_mem_t backing); sp_mem_t sp_mem_tracking_as_allocator(sp_mem_tracking_t* t); void sp_mem_tracking_dump(sp_mem_tracking_t* t); void sp_mem_tracking_deinit(sp_mem_tracking_t* t); -void* sp_mem_tracking_on_alloc(void* ud, sp_mem_alloc_mode_t mode, u64 size, void* ptr); +void* sp_mem_tracking_on_alloc(void* ud, sp_mem_alloc_mode_t mode, u64 size, void* ptr, u64 old_size); bool sp_mem_tracking_ok(sp_mem_tracking_t* mem); #endif @@ -308,12 +309,13 @@ static u32 sp_mem_tracking_peek_magic(void* ptr) { return magic; } -static void sp_mem_tracking_do_free(sp_mem_tracking_t* t, void* ptr) { +static void sp_mem_tracking_do_free(sp_mem_tracking_t* t, void* ptr, u64 size) { if (!ptr) return; u32 magic = sp_mem_tracking_peek_magic(ptr); if (magic == SP_MEM_TRACKING_LIVE_MAGIC) { sp_mem_tracking_node_t* node = sp_mem_tracking_header(ptr); + if (node->size != size) t->bad_sizes++; sp_mem_tracking_unlink(&t->live, node); node->magic = SP_MEM_TRACKING_FREED_MAGIC; t->live_count--; @@ -331,9 +333,9 @@ static void sp_mem_tracking_do_free(sp_mem_tracking_t* t, void* ptr) { } } -static void* sp_mem_tracking_do_realloc(sp_mem_tracking_t* t, void* old, u64 size) { +static void* sp_mem_tracking_do_realloc(sp_mem_tracking_t* t, void* old, u64 size, u64 old_size) { if (!old) return sp_mem_tracking_do_alloc(t, size); - if (!size) { sp_mem_tracking_do_free(t, old); return SP_NULLPTR; } + if (!size) { sp_mem_tracking_do_free(t, old, old_size); return SP_NULLPTR; } u32 magic = sp_mem_tracking_peek_magic(old); if (magic != SP_MEM_TRACKING_LIVE_MAGIC) { @@ -342,21 +344,22 @@ static void* sp_mem_tracking_do_realloc(sp_mem_tracking_t* t, void* old, u64 siz return SP_NULLPTR; } sp_mem_tracking_node_t* node = sp_mem_tracking_header(old); - if (node->size >= size) return old; + if (node->size != old_size) t->bad_sizes++; + if (node->size == size) return old; void* fresh = sp_mem_tracking_do_alloc(t, size); if (!fresh) return SP_NULLPTR; - sp_mem_copy(fresh, old, node->size); - sp_mem_tracking_do_free(t, old); + sp_mem_copy(fresh, old, sp_min(node->size, size)); + sp_mem_tracking_do_free(t, old, node->size); return fresh; } -void* sp_mem_tracking_on_alloc(void* ud, sp_mem_alloc_mode_t mode, u64 size, void* ptr) { +void* sp_mem_tracking_on_alloc(void* ud, sp_mem_alloc_mode_t mode, u64 size, void* ptr, u64 old_size) { sp_mem_tracking_t* t = (sp_mem_tracking_t*)ud; switch (mode) { case SP_ALLOCATOR_MODE_ALLOC: return sp_mem_tracking_do_alloc(t, size); - case SP_ALLOCATOR_MODE_RESIZE: return sp_mem_tracking_do_realloc(t, ptr, size); - case SP_ALLOCATOR_MODE_FREE: sp_mem_tracking_do_free(t, ptr); return SP_NULLPTR; + case SP_ALLOCATOR_MODE_RESIZE: return sp_mem_tracking_do_realloc(t, ptr, size, old_size); + case SP_ALLOCATOR_MODE_FREE: sp_mem_tracking_do_free(t, ptr, old_size); return SP_NULLPTR; default: return SP_NULLPTR; } } @@ -378,11 +381,12 @@ sp_mem_t sp_mem_tracking_as_allocator(sp_mem_tracking_t* t) { } void sp_mem_tracking_dump(sp_mem_tracking_t* t) { - sp_log("tracking: live={} bytes={} double_frees={} wild_frees={}", + sp_log("tracking: live={} bytes={} double_frees={} wild_frees={} bad_sizes={}", sp_fmt_uint(t->live_count), sp_fmt_uint(t->live_bytes), sp_fmt_uint(t->double_frees), - sp_fmt_uint(t->wild_frees)); + sp_fmt_uint(t->wild_frees), + sp_fmt_uint(t->bad_sizes)); for (sp_mem_tracking_node_t* n = t->live; n; n = n->next) { sp_log(" #{} size={}", sp_fmt_uint(n->id), sp_fmt_uint(n->size)); } @@ -392,13 +396,13 @@ void sp_mem_tracking_deinit(sp_mem_tracking_t* t) { sp_mem_tracking_node_t* n = t->live; while (n) { sp_mem_tracking_node_t* next = n->next; - sp_free(t->backing, n); + sp_free(t->backing, n, n->size + sizeof(sp_mem_tracking_node_t)); n = next; } n = t->freed; while (n) { sp_mem_tracking_node_t* next = n->next; - sp_free(t->backing, n); + sp_free(t->backing, n, n->size + sizeof(sp_mem_tracking_node_t)); n = next; } sp_mem_zero(t, sizeof(*t)); @@ -408,7 +412,8 @@ bool sp_mem_tracking_ok(sp_mem_tracking_t* mem) { bool ok = (mem->live_count == 0) && (mem->double_frees == 0) && - (mem->wild_frees == 0); + (mem->wild_frees == 0) && + (mem->bad_sizes == 0); if (!ok) sp_mem_tracking_dump(mem); return ok; } diff --git a/test/tools/utest.h b/test/tools/utest.h index 92e511d..fabf20d 100644 --- a/test/tools/utest.h +++ b/test/tools/utest.h @@ -91,10 +91,38 @@ #endif +typedef struct SP_ALIGNED utest_alloc_header_s { + u64 size; +} utest_alloc_header_t; + +static UTEST_INLINE void *utest_malloc(u64 size) { + utest_alloc_header_t *header = UTEST_PTR_CAST( + utest_alloc_header_t *, sp_mem_os_alloc(size + sizeof(utest_alloc_header_t))); + if (UTEST_NULL == header) { + return UTEST_NULL; + } + header->size = size; + return header + 1; +} + +static UTEST_INLINE void utest_free(void *const pointer) { + if (UTEST_NULL == pointer) { + return; + } + utest_alloc_header_t *header = UTEST_PTR_CAST(utest_alloc_header_t *, pointer) - 1; + sp_mem_os_free(header, header->size + sizeof(utest_alloc_header_t)); +} + static UTEST_INLINE void *utest_realloc(void *const pointer, u64 new_size) { - void *const new_pointer = sp_mem_os_realloc(pointer, new_size); + void *const new_pointer = utest_malloc(new_size); if (UTEST_NULL == new_pointer) { - sp_mem_os_free(pointer); + utest_free(pointer); + return UTEST_NULL; + } + if (UTEST_NULL != pointer) { + utest_alloc_header_t *header = UTEST_PTR_CAST(utest_alloc_header_t *, pointer) - 1; + sp_mem_copy(new_pointer, pointer, sp_min(header->size, new_size)); + utest_free(pointer); } return new_pointer; } @@ -580,9 +608,9 @@ static UTEST_INLINE int utest_strncmp(const c8 *a, const c8 *b, u32 n) { const u64 set_size = sizeof(set_part); \ const c8 test_part[] = #NAME; \ const u64 test_size = sizeof(test_part); \ - c8 *name = UTEST_PTR_CAST(c8 *, sp_mem_os_alloc(name_size)); \ - c8 *set = UTEST_PTR_CAST(c8 *, sp_mem_os_alloc(set_size)); \ - c8 *test = UTEST_PTR_CAST(c8 *, sp_mem_os_alloc(test_size)); \ + c8 *name = UTEST_PTR_CAST(c8 *, utest_malloc(name_size)); \ + c8 *set = UTEST_PTR_CAST(c8 *, utest_malloc(set_size)); \ + c8 *test = UTEST_PTR_CAST(c8 *, utest_malloc(test_size)); \ utest_state.tests = UTEST_PTR_CAST( \ struct utest_test_state_s *, \ utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \ @@ -599,13 +627,13 @@ static UTEST_INLINE int utest_strncmp(const c8 *a, const c8 *b, u32 n) { sp_mem_copy(test, test_part, test_size); \ } else { \ if (utest_state.tests) { \ - sp_mem_os_free(utest_state.tests); \ + utest_free(utest_state.tests); \ utest_state.tests = UTEST_NULL; \ } \ if (name) { \ - sp_mem_os_free(name); \ - sp_mem_os_free(set); \ - sp_mem_os_free(test); \ + utest_free(name); \ + utest_free(set); \ + utest_free(test); \ } \ } \ } \ @@ -651,9 +679,9 @@ static UTEST_INLINE int utest_strncmp(const c8 *a, const c8 *b, u32 n) { const u64 set_size = sizeof(set_part); \ const c8 test_part[] = #NAME; \ const u64 test_size = sizeof(test_part); \ - c8 *name = UTEST_PTR_CAST(c8 *, sp_mem_os_alloc(name_size)); \ - c8 *set = UTEST_PTR_CAST(c8 *, sp_mem_os_alloc(set_size)); \ - c8 *test = UTEST_PTR_CAST(c8 *, sp_mem_os_alloc(test_size)); \ + c8 *name = UTEST_PTR_CAST(c8 *, utest_malloc(name_size)); \ + c8 *set = UTEST_PTR_CAST(c8 *, utest_malloc(set_size)); \ + c8 *test = UTEST_PTR_CAST(c8 *, utest_malloc(test_size)); \ \ utest_state.tests = UTEST_PTR_CAST( \ struct utest_test_state_s *, \ @@ -671,13 +699,13 @@ static UTEST_INLINE int utest_strncmp(const c8 *a, const c8 *b, u32 n) { sp_mem_copy(test, test_part, test_size); \ } else { \ if (utest_state.tests) { \ - sp_mem_os_free(utest_state.tests); \ + utest_free(utest_state.tests); \ utest_state.tests = UTEST_NULL; \ } \ if (name) { \ - sp_mem_os_free(name); \ - sp_mem_os_free(set); \ - sp_mem_os_free(test); \ + utest_free(name); \ + utest_free(set); \ + utest_free(test); \ } \ } \ } \ @@ -716,7 +744,7 @@ static UTEST_INLINE int utest_strncmp(const c8 *a, const c8 *b, u32 n) { sp_str_t fmtd = sp_fmt(sp_mem_get_scratch(), "{}/{}", sp_fmt_cstr(name_part), \ sp_fmt_uint(i)).value; \ u64 name_size = fmtd.len + 1; \ - c8 *name = UTEST_PTR_CAST(c8 *, sp_mem_os_alloc(name_size)); \ + c8 *name = UTEST_PTR_CAST(c8 *, utest_malloc(name_size)); \ utest_state.tests = UTEST_PTR_CAST( \ struct utest_test_state_s *, \ utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \ @@ -730,11 +758,11 @@ static UTEST_INLINE int utest_strncmp(const c8 *a, const c8 *b, u32 n) { name[fmtd.len] = '\0'; \ } else { \ if (utest_state.tests) { \ - sp_mem_os_free(utest_state.tests); \ + utest_free(utest_state.tests); \ utest_state.tests = UTEST_NULL; \ } \ if (name) { \ - sp_mem_os_free(name); \ + utest_free(name); \ } \ } \ } \ @@ -1099,12 +1127,12 @@ s32 utest_main(s32 argc, const c8 **argv) { cleanup: for (index = 0; index < utest_state.tests_length; index++) { - sp_mem_os_free(UTEST_PTR_CAST(void *, utest_state.tests[index].name)); + utest_free(UTEST_PTR_CAST(void *, utest_state.tests[index].name)); } - sp_mem_os_free(UTEST_PTR_CAST(void *, skipped_testcases)); - sp_mem_os_free(UTEST_PTR_CAST(void *, failed_testcases)); - sp_mem_os_free(UTEST_PTR_CAST(void *, utest_state.tests)); + utest_free(UTEST_PTR_CAST(void *, skipped_testcases)); + utest_free(UTEST_PTR_CAST(void *, failed_testcases)); + utest_free(UTEST_PTR_CAST(void *, utest_state.tests)); if (utest_state.has_output) { sp_io_file_writer_close(&utest_state.output); diff --git a/tools/wip/sp_elf.h b/tools/wip/sp_elf.h index f4ed53c..9724c54 100644 --- a/tools/wip/sp_elf.h +++ b/tools/wip/sp_elf.h @@ -266,8 +266,8 @@ void sp_elf_buffer_grow(sp_elf_buffer_t* buffer, u64 size) { capacity *= 2; } + buffer->data = (u8*)sp_mem_allocator_realloc(buffer->mem, buffer->data, buffer->capacity, capacity); buffer->capacity = capacity; - buffer->data = (u8*)sp_mem_allocator_realloc(buffer->mem, buffer->data, capacity); } void* sp_elf_section_reserve_aligned(sp_elf_section_t* section, u64 size, u64 align) { @@ -707,7 +707,7 @@ sp_elf_t* sp_elf_read_from_file(sp_mem_t mem, sp_str_t path) { return SP_NULLPTR; } sp_elf_t* elf = sp_elf_read(mem, (const u8*)bytes.data, bytes.len); - sp_free(mem, (void*)bytes.data); + sp_free(mem, (void*)bytes.data, bytes.len); return elf; }