diff --git a/src/jalloc.c b/src/jalloc.c index 4bd6120..7614256 100644 --- a/src/jalloc.c +++ b/src/jalloc.c @@ -1,22 +1,51 @@ #include #include #include +#include #define HEAP_SIZE (1024 * 1024 * 2) -#define ALIGNMENT 8 +#define ALIGNMENT 16 +#define HEADER_SIZE 32 +#define FOOTER_SIZE 16 static uint8_t heap[HEAP_SIZE]; static uint8_t *heap_ptr = heap; +struct Header { + size_t size; + bool is_free; + struct Header *next; +}; + +struct Footer { + struct Header *header; +}; + +size_t next_multiple_of_align(size_t size) { + return ((size + (ALIGNMENT - 1)) >> 4) << 4; +} + /** * Allocate memory via bump allocation */ void *jalloc(size_t size) { - if (heap_ptr + size > heap + sizeof(heap)) return NULL; - void *ptr = heap_ptr; - heap_ptr += size; + // Total size of allocation = HEADER(padded to ALIGNMENT) + size(padded to ALIGNMENT) + FOOTER(padded to ALIGNMENT) + size_t aligned_size = next_multiple_of_align(size); + void *ptr = heap_ptr + HEADER_SIZE; + struct Header *hdr = (struct Header *)heap_ptr; + struct Footer *ftr = (struct Footer *)(ptr + aligned_size); + if (ftr + FOOTER_SIZE > heap + sizeof(heap)) return NULL; + hdr->size = size; + hdr->next = (struct Header *)heap_ptr; + hdr->is_free = false; + ftr->header = hdr; + heap_ptr = (void *) ftr + FOOTER_SIZE; // set next ptr return ptr; } -void jfree(void *ptr) {} +void jfree(void *ptr) { + struct Header *hdr = (struct Header *)(ptr-HEADER_SIZE); + struct Footer *ftr = (struct Footer *)(hdr->next-FOOTER_SIZE); + hdr->is_free = true; +} diff --git a/src/jalloc.h b/src/jalloc.h index cf657ed..d9b2adb 100644 --- a/src/jalloc.h +++ b/src/jalloc.h @@ -1,3 +1,4 @@ #include void* jalloc(size_t size); +void jfree(void* ptr); diff --git a/src/main.c b/src/main.c index 0ee2909..09f7fe6 100644 --- a/src/main.c +++ b/src/main.c @@ -1,106 +1,169 @@ #include "jalloc.h" #include #include -#include #include -void test_jalloc(void) { - int passed = 0, failed = 0; +static int g_passed = 0; +static int g_failed = 0; - // --- Test 1: Basic write/read --- - { - size_t size = 64; - uint8_t *buf = (uint8_t *)jalloc(size); - if (!buf) { - printf("[FAIL] Test 1: jalloc returned NULL for size %zu\n", size); - failed++; - } else { - for (size_t i = 0; i < size; i++) buf[i] = (uint8_t)i; - int ok = 1; - for (size_t i = 0; i < size; i++) { - if (buf[i] != (uint8_t)i) { ok = 0; break; } - } - printf("[%s] Test 1: sequential byte pattern (%zu bytes)\n", - ok ? "PASS" : "FAIL", size); - ok ? passed++ : failed++; - } +#define ASSERT(cond, msg) \ + do { \ + if (cond) { \ + printf("[PASS] %s\n", (msg)); \ + g_passed++; \ + } else { \ + printf("[FAIL] %s (line %d)\n", (msg), __LINE__); \ + g_failed++; \ + } \ + } while (0) + +static void test_single_byte(void) { + uint8_t *p = jalloc(1); + ASSERT(p != NULL, "single byte: allocation succeeds"); + if (!p) return; + + *p = 0x42; + ASSERT(*p == 0x42, "single byte: read-back correct"); + jfree(p); +} + +static void test_sequential_pattern(void) { + const size_t n = 256; + uint8_t *p = jalloc(n); + ASSERT(p != NULL, "sequential pattern: allocation succeeds"); + if (!p) return; + + for (size_t i = 0; i < n; i++) p[i] = (uint8_t)i; + + int ok = 1; + for (size_t i = 0; i < n; i++) + if (p[i] != (uint8_t)i) { ok = 0; break; } + + ASSERT(ok, "sequential pattern: all bytes intact"); + jfree(p); +} + +static void test_no_overlap(void) { + const size_t n = 256; + uint8_t *a = jalloc(n); + uint8_t *b = jalloc(n); + ASSERT(a != NULL && b != NULL, "no overlap: both allocations succeed"); + if (!a || !b) { jfree(a); jfree(b); return; } + + memset(a, 0xAA, n); + memset(b, 0xBB, n); + + int ok = 1; + for (size_t i = 0; i < n; i++) + if (a[i] != 0xAA || b[i] != 0xBB) { ok = 0; break; } + + ASSERT(ok, "no overlap: writes are isolated"); + jfree(a); + jfree(b); +} + +static void test_string(void) { + const char *msg = "Hello, jalloc!"; + size_t len = strlen(msg) + 1; + char *buf = jalloc(len); + ASSERT(buf != NULL, "string: allocation succeeds"); + if (!buf) return; + + strcpy(buf, msg); + ASSERT(strcmp(buf, msg) == 0, "string: content matches"); + jfree(buf); +} + +static void test_large_allocation(void) { + const size_t n = 1024 * 1024; // 1 MiB + uint8_t *p = jalloc(n); + ASSERT(p != NULL, "large alloc: allocation succeeds (1 MiB)"); + if (!p) return; + + memset(p, 0xCD, n); + + int ok = 1; + for (size_t i = 0; i < n; i++) + if (p[i] != 0xCD) { ok = 0; break; } + + ASSERT(ok, "large alloc: all bytes intact"); + jfree(p); +} + +static void test_many_allocations(void) { + const int count = 1000; + const size_t n = 64; + uint8_t *ptrs[1000] = {0}; + int alloc_ok = 1; + + for (int i = 0; i < count; i++) { + ptrs[i] = jalloc(n); + if (!ptrs[i]) { alloc_ok = 0; break; } + memset(ptrs[i], (uint8_t)i, n); + } + ASSERT(alloc_ok, "many allocs: 1000 allocations all succeed"); + + int content_ok = 1; + for (int i = 0; i < count; i++) { + if (!ptrs[i]) break; + for (size_t j = 0; j < n; j++) + if (ptrs[i][j] != (uint8_t)i) { content_ok = 0; break; } + jfree(ptrs[i]); + } + ASSERT(content_ok, "many allocs: all bytes intact across siblings"); +} + +static void test_free_and_reuse(void) { + const size_t n = 128; + uint8_t *a = jalloc(n); + ASSERT(a != NULL, "free/reuse: first allocation succeeds"); + if (!a) return; + + memset(a, 0x11, n); + jfree(a); + + uint8_t *b = jalloc(n); + ASSERT(b != NULL, "free/reuse: allocation after free succeeds"); + if (!b) return; + + memset(b, 0x22, n); + + int ok = 1; + for (size_t i = 0; i < n; i++) + if (b[i] != 0x22) { ok = 0; break; } + + ASSERT(ok, "free/reuse: memory is writable after reuse"); + jfree(b); +} + +static void test_alignment(void) { + // Test power-of-two sizes from 1 to 128 bytes + void *ptrs[8]; + int ok = 1; + + for (int i = 0; i < 8; i++) { + ptrs[i] = jalloc((size_t)1 << i); + if (!ptrs[i] || (uintptr_t)ptrs[i] % sizeof(void *) != 0) + ok = 0; } - // --- Test 2: Multiple independent allocations don't overlap --- - { - size_t size = 128; - uint8_t *a = (uint8_t *)jalloc(size); - uint8_t *b = (uint8_t *)jalloc(size); - if (!a || !b) { - printf("[FAIL] Test 2: jalloc returned NULL\n"); - failed++; - } else { - memset(a, 0xAA, size); - memset(b, 0xBB, size); - int ok = 1; - for (size_t i = 0; i < size; i++) { - if (a[i] != 0xAA || b[i] != 0xBB) { ok = 0; break; } - } - printf("[%s] Test 2: two allocations don't overlap (%zu bytes each)\n", - ok ? "PASS" : "FAIL", size); - ok ? passed++ : failed++; - } - } + ASSERT(ok, "alignment: all allocations are pointer-aligned"); - // --- Test 3: Small allocation (1 byte) --- - { - uint8_t *buf = (uint8_t *)jalloc(1); - if (!buf) { - printf("[FAIL] Test 3: jalloc returned NULL for 1 byte\n"); - failed++; - } else { - *buf = 0x42; - int ok = (*buf == 0x42); - printf("[%s] Test 3: single byte allocation\n", ok ? "PASS" : "FAIL"); - ok ? passed++ : failed++; - } - } - - // --- Test 4: Large allocation --- - { - size_t size = 1024 * 1024; // 1 MiB - uint8_t *buf = (uint8_t *)jalloc(size); - if (!buf) { - printf("[FAIL] Test 4: jalloc returned NULL for %zu bytes\n", size); - failed++; - } else { - memset(buf, 0xCD, size); - int ok = 1; - for (size_t i = 0; i < size; i++) { - if (buf[i] != 0xCD) { ok = 0; break; } - } - printf("[%s] Test 4: large allocation (%zu bytes)\n", - ok ? "PASS" : "FAIL", size); - ok ? passed++ : failed++; - } - } - - // --- Test 5: String write/read --- - { - const char *msg = "Hello, jalloc!"; - size_t size = strlen(msg) + 1; - char *buf = (char *)jalloc(size); - if (!buf) { - printf("[FAIL] Test 5: jalloc returned NULL\n"); - failed++; - } else { - strcpy(buf, msg); - int ok = (strcmp(buf, msg) == 0); - printf("[%s] Test 5: string integrity (\"%s\")\n", - ok ? "PASS" : "FAIL", buf); - ok ? passed++ : failed++; - } - } - - printf("\n=== Results: %d passed, %d failed ===\n", passed, failed); + for (int i = 0; i < 8; i++) jfree(ptrs[i]); } int main(void) { - test_jalloc(); - return 0; + printf("=== jalloc test suite ===\n\n"); + + test_single_byte(); + test_sequential_pattern(); + test_no_overlap(); + test_string(); + test_large_allocation(); + test_many_allocations(); + test_free_and_reuse(); + test_alignment(); + + printf("\n=== %d passed, %d failed ===\n", g_passed, g_failed); + return g_failed > 0 ? 1 : 0; }