/* * axl_memory_tests.c — Comprehensive unit tests for axl_memory.h */ #include "axl_memory.h" #include "axl_koan.h" #include /* ------------------------------------------------------------------ */ /* Basic allocation & initialization */ /* ------------------------------------------------------------------ */ KOAN(init_called) { void* p = axl_malloc(1); ASSERT_NOT_NULL(p); axl_free(p); } KOAN(malloc_returns_different_pointers) { void* a = axl_malloc(16); void* b = axl_malloc(32); ASSERT_NOT_NULL(a); ASSERT_NOT_NULL(b); ASSERT_TRUE(a != b); axl_free(a); axl_free(b); } KOAN(malloc_exhaustion_returns_null) { void* p = axl_malloc(AXL_HEAP_SIZE + 4096); /* definitely too big */ ASSERT_NULL(p); } /* ------------------------------------------------------------------ */ /* Realloc behavior (strictly per C standard) */ /* ------------------------------------------------------------------ */ KOAN(realloc_null_acts_like_malloc) { void* p = axl_realloc(NULL, 64); ASSERT_NOT_NULL(p); axl_memset(p, 0x55, 64); axl_free(p); } KOAN(realloc_zero_size_frees_and_returns_null_or_valid) { void* p = axl_malloc(100); ASSERT_NOT_NULL(p); void* q = axl_realloc(p, 0); if (q != NULL) axl_free(q); /* Original p is freed regardless */ } KOAN(realloc_enlarge_preserves_content) { void* p = axl_malloc(32); axl_memset(p, 0xCD, 32); void* q = axl_realloc(p, 128); ASSERT_NOT_NULL(q); for (int i = 0; i < 32; i++) ASSERT_INT_EQ(0xCD, ((u8*)q)[i]); axl_free(q); } KOAN(realloc_shrink_preserves_prefix) { void* p = axl_malloc(256); axl_memset(p, 0xAB, 256); void* q = axl_realloc(p, 64); ASSERT_NOT_NULL(q); for (int i = 0; i < 64; i++) ASSERT_INT_EQ(0xAB, ((u8*)q)[i]); axl_free(q); } KOAN(realloc_same_size_returns_same_or_equivalent) { void* p = axl_malloc(100); p = axl_realloc(p, 100); ASSERT_NOT_NULL(p); /* May return same or different pointer */ axl_free(p); } /* ------------------------------------------------------------------ */ /* Memory operations */ /* ------------------------------------------------------------------ */ KOAN(memset_fills_correctly) { void* p = axl_malloc(64); axl_memset(p, 0x55, 64); for (int i = 0; i < 64; i++) ASSERT_INT_EQ(0x55, ((u8*)p)[i]); axl_free(p); } KOAN(memset_zero_bytes_is_nop) { void* p = axl_malloc(16); axl_memset(p, 0xFF, 16); axl_memset(p, 0x00, 0); /* should not change anything */ for (int i = 0; i < 16; i++) ASSERT_INT_EQ(0xFF, ((u8*)p)[i]); axl_free(p); } KOAN(memcpy_copies_exact_bytes) { u8 src[32]; for (int i = 0; i < 32; i++) src[i] = (u8)i; void* dst = axl_malloc(32); axl_memcpy(dst, src, 32); ASSERT_INT_EQ(0, memcmp(dst, src, 32)); axl_free(dst); } KOAN(memcpy_zero_bytes_is_nop) { u8 data[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}; void* p = axl_malloc(16); axl_memcpy(p, data, 16); axl_memcpy(p, "junk", 0); /* must not modify */ ASSERT_INT_EQ(0, memcmp(p, data, 16)); axl_free(p); } KOAN(memcmp_returns_correct_sign) { u8 a[] = {0, 0, 0, 0}; u8 b[] = {0, 0, 0, 1}; u8 c[] = {0, 0, 1, 0}; ASSERT_INT_EQ(0, axl_memcmp(a, a, 4)); ASSERT_TRUE(axl_memcmp(a, b, 4) < 0); ASSERT_TRUE(axl_memcmp(b, a, 4) > 0); ASSERT_TRUE(axl_memcmp(a, c, 3) < 0 ); ASSERT_TRUE(axl_memcmp(a, b, 2) == 0); ASSERT_TRUE(axl_memcmp(a, c, 2) == 0); ASSERT_TRUE(axl_memcmp(c, b, 2) == 0); ASSERT_TRUE(axl_memcmp(a, c, 4) < 0); } KOAN(memcmp_zero_length_returns_zero) { u8 x = 0xFF, y = 0x00; ASSERT_INT_EQ(0, axl_memcmp(&x, &y, 0)); } /* ------------------------------------------------------------------ */ /* Double-free and use-after-free detection (indirect) */ /* ------------------------------------------------------------------ */ KOAN(double_free_does_not_crash) { void* p = axl_malloc(64); ASSERT_NOT_NULL(p); axl_free(p); axl_free(p); /* should be ignored or handled safely */ } /* ------------------------------------------------------------------ */ /* Large and boundary allocations */ /* ------------------------------------------------------------------ */ KOAN(large_allocation_near_heap_limit) { /* Allocate almost entire heap */ void* p = axl_malloc(AXL_HEAP_SIZE - 1024); ASSERT_NOT_NULL(p); /* may pass if overhead is small */ if (p) axl_free(p); } KOAN(allocation_of_max_size_fails) { void* p = axl_malloc(AXL_HEAP_SIZE); ASSERT_NULL(p); } /* ------------------------------------------------------------------ */ /* Stress: many small allocations */ /* ------------------------------------------------------------------ */ KOAN(many_small_allocations) { #define N 1000 void* ptrs[N]; for (int i = 0; i < N; i++) { ptrs[i] = axl_malloc(16); ASSERT_NOT_NULL(ptrs[i]); *(u32*)ptrs[i] = 0xDEADBEEF; } for (int i = 0; i < N; i++) { ASSERT_INT_EQ(0xDEADBEEF, *(u32*)ptrs[i]); axl_free(ptrs[i]); } } /* ------------------------------------------------------------------ */ /* Main */ /* ------------------------------------------------------------------ */ int main(void) { axl_init(); return koan_run_all(); }