diff options
| author | Ethan Werner <mail@ethanwerner.com> | 2026-06-09 01:17:41 +0400 |
|---|---|---|
| committer | Ethan Werner <mail@ethanwerner.com> | 2026-06-09 01:17:41 +0400 |
| commit | 96ecf29e8be977f51f351308ef2c7c492bb829aa (patch) | |
| tree | c664aa61262e6f7627a732f0e4fbb84281b99952 /include/pool.h | |
| parent | f6a144987cc403de8ad6bddd055f756120f8d405 (diff) | |
refactor
Diffstat (limited to 'include/pool.h')
| -rwxr-xr-x | include/pool.h | 123 |
1 files changed, 85 insertions, 38 deletions
diff --git a/include/pool.h b/include/pool.h index d418142..7121f18 100755 --- a/include/pool.h +++ b/include/pool.h @@ -1,38 +1,43 @@ // pool.h - Fixed block size, free list based, memory pool +// +// Note: block_s must be >= sizeof(void*) and aligned to maintain proper +// pointer alignment for returned blocks. +// +// Thread safety: Not thread-safe. External synchronization required. +// Memory safety: pool_free validates pointer range, alignment, and detects +// double-free via free-list walk (O(n) in number of free blocks). +// Invalid frees are silently ignored. #ifndef POOL_H #define POOL_H -#include <complex.h> -#include <setjmp.h> -#include <stdint.h> +#include "type.h" typedef struct pool_t { - uint32_t block_n; // Block capacity - uint32_t block_i; // Block count - uint32_t block_s; // Block size in bytes - void *data; // Blocks - void *free; // Free chunk + u32 block_n; // Block capacity + u32 block_i; // Block count + u32 block_s; // Block size in bytes + void *data; // Blocks + void *free; // Free chunk } pool_t; -pool_t *pool_init(uint32_t, uint32_t); -void pool_fini(pool_t *); +pool_t *pool_init(u32, u32); +void pool_fini(pool_t **); void *pool_malloc(pool_t *); void pool_free(pool_t *, void *); +u32 pool_capacity(const pool_t *); +u32 pool_size(const pool_t *); + #endif // POOL_H -#define POOL_IMPLEMENTATION #ifdef POOL_IMPLEMENTATION // IMPLEMENTATION -#define POOL_MULTIPLIER_RESIZE 2 -#define POOL_BLOCK_N 10 - -#include <stdio.h> +#include <stddef.h> +#include <assert.h> #include <stdlib.h> -static void pool_print(pool_t *pool); -static void pool_free_list(uintptr_t *, uint32_t, uint32_t); +static void pool_free_list(uintptr_t *, u32, u32); // pool_init() // @@ -41,16 +46,32 @@ static void pool_free_list(uintptr_t *, uint32_t, uint32_t); // block_s - The size of a block in bytes // block_n - The number of initial blocks -pool_t *pool_init( uint32_t block_s, uint32_t block_n) { +pool_t *pool_init(u32 block_s, u32 block_n) { + if (block_n == 0) + return NULL; + if (block_s < sizeof(void *) || block_s % sizeof(void *) != 0) + return NULL; + pool_t *pool = (pool_t *)malloc(sizeof(pool_t)); + if (!pool) + return NULL; // Set size and count pool->block_n = block_n; pool->block_s = block_s; + pool->block_i = 0; + if (block_n != 0 && block_s > SIZE_MAX / (size_t)block_n) { + free(pool); + return NULL; + } pool->data = calloc(block_n, block_s); - pool->free = pool->data; + if (!pool->data) { + free(pool); + return NULL; + } + pool->free = pool->data; pool_free_list((uintptr_t *)pool->data, block_n, block_s); return pool; @@ -63,6 +84,8 @@ pool_t *pool_init( uint32_t block_s, uint32_t block_n) { // pool - A pointer to the pool object void *pool_malloc(pool_t *pool) { + if (!pool) + return NULL; uintptr_t *free = (uintptr_t *)pool->free; if (free) { @@ -80,6 +103,31 @@ void *pool_malloc(pool_t *pool) { // pool - A pointer to the pool object void pool_free(pool_t *pool, void *p) { + if (!pool || !p || !pool->data) + return; + // Validate pointer is within pool range + u8 *base = (u8 *)pool->data; + u8 *ptr = (u8 *)p; + if ((u64)pool->block_n > UINT64_MAX / (u64)pool->block_s) + return; + u64 total = (u64)pool->block_n * pool->block_s; + if (total > SIZE_MAX) + return; + u8 *end = base + (size_t)total; + if (ptr < base || ptr >= end) + return; + // Validate pointer is aligned to block size + if ((ptr - base) % pool->block_s != 0) + return; + // Check for double-free: walk free list to detect already-freed block + { + uintptr_t *cur = (uintptr_t *)pool->free; + while (cur) { + if ((uintptr_t)cur == (uintptr_t)p) + return; + cur = (uintptr_t *)*cur; + } + } // Convert the pointer into a usable type uintptr_t *free = (uintptr_t *)p; @@ -89,30 +137,21 @@ void pool_free(pool_t *pool, void *p) { // Set the pool's free head to the newly freed pointer pool->free = (void *)free; - pool->block_i--; + if (pool->block_i > 0) + pool->block_i--; } -uint32_t pool_capacity(pool_t *pool) { - return pool->block_n; -} +u32 pool_capacity(const pool_t *pool) { if (!pool) return 0; return pool->block_n; } -uint32_t pool_size(pool_t *pool) { - return pool->block_i; -} +u32 pool_size(const pool_t *pool) { if (!pool) return 0; return pool->block_i; } -static void pool_print(pool_t *pool) { - uintptr_t *ptr = (uintptr_t *)pool->free; - while (((uintptr_t)ptr - (uintptr_t)pool->data) < - pool->block_n * pool->block_s) { - printf("%p %lx\n", ptr, *ptr); - ptr = (uintptr_t *)(((uint8_t *)ptr) + pool->block_s); - } -} +static void pool_free_list(uintptr_t *block, u32 block_n, + u32 block_s) { + if (block_n == 0) + return; -static void pool_free_list(uintptr_t *block, uint32_t block_n, - uint32_t block_s) { - uint8_t *ptr = (uint8_t *)block; - for (int i = 0; i < block_n - 1; i++) { + u8 *ptr = (u8 *)block; + for (u32 i = 0; i < block_n - 1; i++) { uintptr_t *tmp = (uintptr_t *)ptr; *tmp = (uintptr_t)ptr + block_s; ptr = ptr + block_s; @@ -121,4 +160,12 @@ static void pool_free_list(uintptr_t *block, uint32_t block_n, *(uintptr_t *)ptr = (uintptr_t)0; } +void pool_fini(pool_t **pool) { + if (pool && *pool) { + free((*pool)->data); + free(*pool); + *pool = NULL; + } +} + #endif // POOL_IMPLEMENTATION |