Skip to content

Commit

Permalink
Improve memory allocator
Browse files Browse the repository at this point in the history
Implement a memory allocator which can `free`, rather than the simple
bump allocator we had before.
  • Loading branch information
0152la committed Aug 13, 2024
1 parent a3268ef commit f740fe9
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 25 deletions.
2 changes: 2 additions & 0 deletions include/comp_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
#define _COMP_UTILS_H

#include <err.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <sys/mman.h>

Expand Down
183 changes: 159 additions & 24 deletions src/comp_utils.c
Original file line number Diff line number Diff line change
@@ -1,51 +1,176 @@
#include "comp_utils.h"

static void *malloc_ptr;
static size_t heap_mem_left;
static size_t mem_left = 0;
static void *heap_header = NULL;
static void *heap_start = NULL;
const static size_t block_metadata_sz = sizeof(void *) + sizeof(size_t);

#define NON_COMP_DEFAULT_SIZE (1024 * 1024 * 1024) // 1 GB

/*******************************************************************************
* Helper functions
******************************************************************************/

static inline void *
get_next(void *addr)
{
return *(void **) ((char *) addr - sizeof(void *));
}

static inline size_t
get_size(void *addr)
{
return *(size_t *) ((char *) addr - block_metadata_sz);
}

static inline size_t
get_next_slot_size(void *addr)
{
return (size_t) get_next(addr) - (uintptr_t) addr - get_size(addr);
}

static inline void
set_next(void *addr, void *next)
{
memcpy((char *) addr - sizeof(void *), &next, sizeof(void *));
}

static inline void
set_size(void *addr, size_t size)
{
memcpy((char *) addr - block_metadata_sz, &size, sizeof(size_t));
}

static inline void
make_new_metadata(void *addr, size_t size, void *next, void *prev)
{
set_next(addr, next);
set_size(addr, size);
if (prev)
{
set_next(prev, addr);
}
}

static inline void
clear_block(void *addr)
{
memset((char *) addr - block_metadata_sz, 0, get_size(addr));
}

/*******************************************************************************
* Main functions
******************************************************************************/

void *
malloc(size_t to_alloc)
{
if (!malloc_ptr)
if (!heap_header)
{
void *__capability ddc = cheri_ddc_get();
void *mem_begin;
if (cheri_base_get(ddc) == 0)
{
malloc_ptr = mmap(0, NON_COMP_DEFAULT_SIZE, PROT_WRITE | PROT_READ,
mem_begin = mmap(0, NON_COMP_DEFAULT_SIZE, PROT_WRITE | PROT_READ,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
heap_mem_left = NON_COMP_DEFAULT_SIZE;
if (malloc_ptr == MAP_FAILED)
if (mem_begin == MAP_FAILED)
{
err(1, "Failed `mmap`");
err(1, "comp_utils: Failed `mmap`");
}
mem_left = NON_COMP_DEFAULT_SIZE;
}
else
{
malloc_ptr = (char *) cheri_address_get(ddc);
mem_begin = (char *) cheri_address_get(ddc);
// TODO move heap to the end of the compartment; currently, it's at
// the beginning of the memory scratch area
heap_mem_left = cheri_length_get(ddc) - cheri_offset_get(ddc);
mem_left = cheri_length_get(ddc) - cheri_offset_get(ddc);
}
heap_start = (char *) mem_begin + sizeof(size_t) + sizeof(void *);
heap_header = heap_start;
}

if (to_alloc > heap_mem_left)
/* We put some metadata at the beginning of each allocated block
// * size_t size
// * void* next_block
*/
size_t to_alloc_total = to_alloc + block_metadata_sz;

// TODO replace with return NULL and check `mem_left` works
if (to_alloc_total > mem_left)
{
errx(1, "Insufficient heap space left.");
errx(1, "comp_utils: Insufficient heap space left.");
}
void *to_ret = malloc_ptr;
memset(to_ret, 0, to_alloc);
malloc_ptr = (char *) malloc_ptr + to_alloc;
heap_mem_left -= to_alloc;
return to_ret;

// Find a sufficiently large block to allocate
void *curr_block = heap_header;
void *prev_block = NULL;
void *next_to_set = NULL;

// Check if we have enough space before the first allocated block
if ((uintptr_t) curr_block - (uintptr_t) heap_start >= to_alloc_total)
{
curr_block = heap_start;
next_to_set = heap_header;
heap_header = curr_block;
}
else
{
while (curr_block)
{
prev_block = curr_block;
if (!get_next(curr_block)
|| get_next_slot_size(curr_block) >= to_alloc_total)
{
next_to_set = get_next(curr_block);
curr_block = (char *) curr_block + get_size(curr_block);
break;
}
curr_block = get_next(curr_block);
}
}

if (curr_block == prev_block)
{
prev_block = NULL;
}
make_new_metadata(curr_block, to_alloc_total, next_to_set, prev_block);

memset(curr_block, 0, to_alloc);
mem_left -= to_alloc_total;
return curr_block;
}

void
free(void *to_free)
{
// TODO temp usage for bump allocator implementation to satisfy compiler
to_free = to_free;
if (!to_free)
{
return;
}

void *curr_block = heap_header;

if (curr_block == to_free)
{
heap_header = get_next(curr_block);
clear_block(curr_block);
return;
}

while (curr_block)
{
if (get_next(curr_block) == to_free)
{
void *free_block = get_next(curr_block);
set_next(curr_block, get_next(free_block));
clear_block(free_block);
mem_left += get_size(to_free) + block_metadata_sz;
return;
}
curr_block = get_next(curr_block);
}
errx(1, "comp_utils: Did not find block to free for addr `%p`!\n", to_free);
}

void *
Expand All @@ -57,15 +182,25 @@ calloc(size_t elem_count, size_t elem_size)
void *
realloc(void *to_realloc, size_t new_size)
{
if (!to_realloc)
if (!to_realloc || get_size(to_realloc) == 0)
{
return malloc(new_size);
}
void *new_alloc = malloc(new_size);
size_t to_copy_size = new_size; // TODO
memcpy(new_alloc, to_realloc, to_copy_size);
free(to_realloc);
return new_alloc;

if (new_size + block_metadata_sz > get_size(to_realloc))
{
void *new_alloc = malloc(new_size);
memcpy(new_alloc, to_realloc, get_size(to_realloc) - block_metadata_sz);
free(to_realloc);
mem_left -= new_size - get_size(to_realloc);
return new_alloc;
}

memset((char *) to_realloc + new_size, 0,
get_size(to_realloc) - new_size - block_metadata_sz);
set_size(to_realloc, new_size + block_metadata_sz);
mem_left += get_size(to_realloc) - new_size;
return to_realloc;
}

void *
Expand Down
15 changes: 15 additions & 0 deletions tests/init_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@
"/lib/libm.so.5",
]

LUA_TESTS_PATH = "./third-party/lua/testes"
LUA_TESTS = [
"calls.lua",
"goto.lua",
"strings.lua",
"tpack.lua",
"tracegc.lua",
"utf8.lua",
]

################################################################################
# Main
################################################################################
Expand All @@ -33,15 +43,20 @@
home_dir = vm_conn.run("echo $HOME", hide = True).stdout.strip()
CHERIBSD_TEST_DIR = os.path.join(home_dir, CHERIBSD_TEST_DIR)
COMP_LIBRARY_PATH = os.path.join(home_dir, COMP_LIBRARY_PATH)
LUA_TESTS_DIR = os.path.join(CHERIBSD_TEST_DIR, "lua")
remote_env = {
'COMP_LIBRARY_PATH': COMP_LIBRARY_PATH,
'LD_LIBRARY_PATH': COMP_LIBRARY_PATH,
}

vm_conn.run(f'mkdir -p {CHERIBSD_TEST_DIR}')
vm_conn.run(f'mkdir -p {COMP_LIBRARY_PATH}')
vm_conn.run(f'mkdir -p {LUA_TESTS_DIR}')
vm_conn.run
for lib in LOCAL_LIBS:
vm_conn.put(lib, remote = f'{COMP_LIBRARY_PATH}', )
for test in LUA_TESTS:
vm_conn.put(os.path.join(LUA_TESTS_PATH, test), remote = f'{LUA_TESTS_DIR}', )
for lib in REMOTE_LIBS:
cmd = f'cd {COMP_LIBRARY_PATH} ; ln -s {lib}'
vm_conn.run(cmd)
Expand Down
70 changes: 69 additions & 1 deletion tests/simple_malloc.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,80 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>

static inline void
check_next(void *addr, void *to_check)
{
assert(*((void **) ((char *) addr - sizeof(void *))) == to_check);
}

int
main(void)
{
const char *hw = "Hello World!";
char *x = malloc(strlen(hw));
const size_t hw_sz = strlen(hw);

char *x = malloc(hw_sz + 1);
strcpy(x, hw);
assert(!strcmp(x, "Hello World!"));

x = realloc(x, hw_sz * 2 + 1);
strcat(x, hw);
assert(!strcmp(x, "Hello World!Hello World!"));

x = realloc(x, hw_sz + 1);
x[strlen(hw)] = '\0';
assert(!strcmp(x, "Hello World!"));

free(x);

const size_t malloc_block_sz = 16;

// Check free
void *tmp01 = malloc(2 * malloc_block_sz);
void *tmp02 = malloc(1 * malloc_block_sz);
free(tmp01);
tmp01 = malloc(2 * malloc_block_sz);
free(tmp02);
free(tmp01);

// Check realloc
void *tmp11 = realloc(NULL, 2 * malloc_block_sz);
void *tmp13 = realloc(NULL, 1 * malloc_block_sz);
void *tmp12 = realloc(tmp11, 2 * malloc_block_sz);

assert(tmp11 == tmp12);

void *tmp14 = realloc(tmp12, 4 * malloc_block_sz);
check_next(tmp13, tmp14);

void *tmp15 = malloc(2 * malloc_block_sz);
check_next(tmp15, tmp13);

free(tmp13);
check_next(tmp15, tmp14);
free(tmp15);
free(tmp14);

// Check finding right block to insert
void *tmp1 = malloc(1 * malloc_block_sz);
void *y = malloc(3 * malloc_block_sz);
void *tmp2 = malloc(1 * malloc_block_sz);
void *tmp3 = malloc(5 * malloc_block_sz);
free(y);
void *tmp4 = malloc(malloc_block_sz);
void *tmp5 = malloc(malloc_block_sz);

assert(tmp1 < tmp4);
assert(tmp1 < tmp5);
assert(tmp4 < tmp2);
assert(tmp5 < tmp2);

free(tmp1);
free(tmp2);
free(tmp3);
free(tmp4);
free(tmp5);

return 0;
}

0 comments on commit f740fe9

Please sign in to comment.