Fix bug and handle more errors
Fix bug where mprotect calls don't match the arena cap increase (https://github.com/olemorud/arena-allocator/issues/1) Handle syscall errors in arena_new() Check for syscall errors in arena_delete() and switch from void to int to return error status.
This commit is contained in:
@@ -15,14 +15,16 @@ typedef struct arena {
|
||||
/**
|
||||
* Allocate a new arena.
|
||||
* The underlying memory is allocated with mmap.
|
||||
* Errors can be checked with `arena_new_failed()`
|
||||
*/
|
||||
arena_t arena_new();
|
||||
|
||||
/**
|
||||
* Delete memory mapped for arena.
|
||||
* Should only be used with arenas from arena_new().
|
||||
* Returns 0 on success, -1 on failure
|
||||
*/
|
||||
void arena_delete(arena_t *a);
|
||||
int arena_delete(arena_t *a);
|
||||
|
||||
/**
|
||||
* Attach an arena to an existing memory region.
|
||||
@@ -41,10 +43,21 @@ static inline void *arena_detatch(arena_t arena)
|
||||
return arena.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if creating new arena failed
|
||||
*/
|
||||
static inline bool arena_new_failed(arena_t *a)
|
||||
{
|
||||
return a->data == NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset an arena.
|
||||
*/
|
||||
void arena_reset(arena_t *a);
|
||||
static inline void arena_reset(arena_t *a)
|
||||
{
|
||||
a->size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate memory from an arena.
|
||||
|
||||
59
src/arena.c
59
src/arena.c
@@ -10,6 +10,7 @@
|
||||
|
||||
#define ARENA_ALIGN (sizeof(void *))
|
||||
#define ARENA_GROW_FACTOR 2UL
|
||||
#define ARENA_OVERCOMMIT_SIZE (1UL << 40UL)
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define arena_err(msg) \
|
||||
@@ -18,53 +19,74 @@
|
||||
#define arena_err(msg)
|
||||
#endif
|
||||
|
||||
static bool arena_grow(struct arena *a)
|
||||
static bool arena_grow(struct arena *a, size_t min_size)
|
||||
{
|
||||
size_t new_cap = a->cap * 2;
|
||||
while (new_cap < min_size) {
|
||||
new_cap *= 2;
|
||||
}
|
||||
|
||||
int ok = mprotect(
|
||||
a->data + a->cap,
|
||||
a->cap * ARENA_GROW_FACTOR,
|
||||
PROT_READ | PROT_WRITE);
|
||||
new_cap - a->cap,
|
||||
PROT_READ | PROT_WRITE
|
||||
);
|
||||
|
||||
if (ok == -1) {
|
||||
arena_err("mprotect");
|
||||
return false;
|
||||
}
|
||||
|
||||
a->cap *= ARENA_GROW_FACTOR;
|
||||
a->cap = new_cap;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void arena_reset(arena_t *a)
|
||||
{
|
||||
a->size = 0;
|
||||
}
|
||||
|
||||
arena_t arena_new()
|
||||
{
|
||||
size_t size = sysconf(_SC_PAGE_SIZE);
|
||||
void *p = mmap(NULL, 1UL << 40UL, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
mprotect(p, size, PROT_READ | PROT_WRITE);
|
||||
if (p == MAP_FAILED)
|
||||
if (size == -1) {
|
||||
arena_err("sysconf");
|
||||
goto sysconf_failed;
|
||||
}
|
||||
|
||||
void *p = mmap(NULL, ARENA_OVERCOMMIT_SIZE, PROT_NONE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
if (p == MAP_FAILED) {
|
||||
arena_err("mmap");
|
||||
goto mmap_failed;
|
||||
}
|
||||
|
||||
int ok = mprotect(p, size, PROT_READ | PROT_WRITE);
|
||||
if (ok == -1) {
|
||||
arena_err("mprotect");
|
||||
goto mprotect_failed;
|
||||
}
|
||||
|
||||
return arena_attach(p, size);
|
||||
|
||||
mprotect_failed:
|
||||
munmap(p, ARENA_OVERCOMMIT_SIZE);
|
||||
mmap_failed:
|
||||
sysconf_failed:
|
||||
return (arena_t) { 0 };
|
||||
}
|
||||
|
||||
void *arena_alloc(arena_t *a, size_t size)
|
||||
void* arena_alloc(arena_t *a, size_t size)
|
||||
{
|
||||
size = (size + ARENA_ALIGN - 1) & ~(ARENA_ALIGN - 1); // align
|
||||
|
||||
void *p = a->data + a->size;
|
||||
a->size += size;
|
||||
if (a->size > a->cap) {
|
||||
if (!arena_grow(a))
|
||||
if (!arena_grow(a, a->size))
|
||||
return NULL;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *arena_calloc(arena_t *a, size_t nmemb, size_t size)
|
||||
void* arena_calloc(arena_t *a, size_t nmemb, size_t size)
|
||||
{
|
||||
void *p = arena_alloc(a, nmemb * size);
|
||||
if (p == NULL)
|
||||
@@ -73,9 +95,14 @@ void *arena_calloc(arena_t *a, size_t nmemb, size_t size)
|
||||
return p;
|
||||
}
|
||||
|
||||
void arena_delete(struct arena *a)
|
||||
int arena_delete(struct arena *a)
|
||||
{
|
||||
munmap(a->data, a->cap);
|
||||
int ok = munmap(a->data, a->cap);
|
||||
if (ok == -1) {
|
||||
arena_err("munmap");
|
||||
return -1;
|
||||
}
|
||||
a->cap = -1;
|
||||
a->size = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user