Skip to content

Commit

Permalink
Correctness fixes and (optional) better C stdlib integration
Browse files Browse the repository at this point in the history
- Add early NULL check to ta_free()
- Add overflow checks in alloc_block() and ta_calloc()
- Clear full block size to 0's in ta_calloc()
- Optionally set errno to ENOMEM when out of memory
- Optionally use memset() to implement memclear()
- Add ta_getsize() to return allocated block size
- Add ta_realloc() (optional, requires memcpy())

ta_getsize() and ta_realloc() are based on ideas from thi-ng#11, but rewritten
to fix various issues in that PR.
  • Loading branch information
jlindgren90 committed Mar 23, 2024
1 parent b60fcd7 commit ccdaa00
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 1 deletion.
68 changes: 67 additions & 1 deletion tinyalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ extern void print_i(size_t);
#define print_i(X)
#endif

/* optional C stdlib integration */
#ifdef TA_USE_STDLIB
#include <errno.h>
#include <string.h>
#endif

typedef struct Block Block;

struct Block {
Expand Down Expand Up @@ -134,6 +140,9 @@ bool ta_init(const void *base, const void *limit, const size_t heap_blocks, cons
}

bool ta_free(void *free) {
if (free == NULL) {
return false;
}
Block *block = heap->used;
Block *prev = NULL;
while (block != NULL) {
Expand All @@ -159,7 +168,11 @@ static Block *alloc_block(size_t num) {
Block *ptr = heap->free;
Block *prev = NULL;
size_t top = heap->top;
size_t orig = num;
num = (num + heap_alignment - 1) & -heap_alignment;
if (num < orig) {
return NULL; // overflow
}
while (ptr != NULL) {
const int is_top = ((size_t)ptr->addr + ptr->size >= top) && ((size_t)ptr->addr + num <= (size_t)heap_limit);
if (is_top || ptr->size >= num) {
Expand Down Expand Up @@ -218,9 +231,15 @@ void *ta_alloc(size_t num) {
if (block != NULL) {
return block->addr;
}
#ifdef TA_USE_STDLIB
errno = ENOMEM;
#endif
return NULL;
}

#ifdef TA_USE_STDLIB
#define memclear(ptr, num) memset((ptr), 0, (num))
#else
static void memclear(void *ptr, size_t num) {
size_t *ptrw = (size_t *)ptr;
size_t numw = (num & -sizeof(size_t)) / sizeof(size_t);
Expand All @@ -233,14 +252,23 @@ static void memclear(void *ptr, size_t num) {
*ptrb++ = 0;
}
}
#endif

void *ta_calloc(size_t num, size_t size) {
size_t orig = num;
num *= size;
if (size != 0 && num / size != orig) {
goto overflow;
}
Block *block = alloc_block(num);
if (block != NULL) {
memclear(block->addr, num);
memclear(block->addr, block->size);
return block->addr;
}
overflow:
#ifdef TA_USE_STDLIB
errno = ENOMEM;
#endif
return NULL;
}

Expand Down Expand Up @@ -268,3 +296,41 @@ size_t ta_num_fresh() {
bool ta_check() {
return heap_max_blocks == ta_num_free() + ta_num_used() + ta_num_fresh();
}

size_t ta_getsize(void *ptr) {
if (ptr == NULL) {
return 0;
}
Block *block = heap->used;
while (block != NULL) {
if (ptr == block->addr) {
return block->size;
}
block = block->next;
}
return 0;
}

/* requires memcpy() */
#ifdef TA_USE_STDLIB
void *ta_realloc(void *ptr, size_t num) {
if (ptr == NULL) {
return ta_alloc(num);
} else if (num == 0) {
ta_free(ptr);
return NULL;
}
size_t size = ta_getsize(ptr);
Block *block = alloc_block(num);
if (block != NULL) {
if (size > num) {
size = num;
}
memcpy(block->addr, ptr, size);
ta_free(ptr);
return block->addr;
}
errno = ENOMEM;
return NULL;
}
#endif
6 changes: 6 additions & 0 deletions tinyalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ bool ta_init(const void *base, const void *limit, const size_t heap_blocks, cons
void *ta_alloc(size_t num);
void *ta_calloc(size_t num, size_t size);
bool ta_free(void *ptr);
size_t ta_getsize(void *ptr);

/* requires memcpy() */
#ifdef TA_USE_STDLIB
void *ta_realloc(void *ptr, size_t num);
#endif

size_t ta_num_free();
size_t ta_num_used();
Expand Down

0 comments on commit ccdaa00

Please sign in to comment.