summaryrefslogtreecommitdiffstats
path: root/include/pool.h
diff options
context:
space:
mode:
authorEthan Werner <mail@ethanwerner.com>2026-06-09 01:17:41 +0400
committerEthan Werner <mail@ethanwerner.com>2026-06-09 01:17:41 +0400
commit96ecf29e8be977f51f351308ef2c7c492bb829aa (patch)
treec664aa61262e6f7627a732f0e4fbb84281b99952 /include/pool.h
parentf6a144987cc403de8ad6bddd055f756120f8d405 (diff)
refactor
Diffstat (limited to 'include/pool.h')
-rwxr-xr-xinclude/pool.h123
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