2025-12-01 19:39:11 +03:00
|
|
|
/*
|
|
|
|
|
* axl_memory_tests.c — Comprehensive unit tests for axl_memory.h
|
|
|
|
|
*/
|
|
|
|
|
#include "axl_memory.h"
|
|
|
|
|
#include "axl_koan.h"
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2025-12-03 17:37:53 +03:00
|
|
|
void* p = axl_malloc(AXL_HEAP_SIZE + 4096);
|
2025-12-01 19:39:11 +03:00
|
|
|
ASSERT_NULL(p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
axl_free(p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
2025-12-03 17:37:53 +03:00
|
|
|
axl_memset(p, 0x00, 0);
|
2025-12-01 19:39:11 +03:00
|
|
|
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);
|
2025-12-03 17:37:53 +03:00
|
|
|
axl_memcpy(p, "junk", 0);
|
2025-12-01 19:39:11 +03:00
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-03 16:49:54 +03:00
|
|
|
KOAN(memchr_finds_character_in_buffer)
|
|
|
|
|
{
|
|
|
|
|
u8 buffer[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
|
|
|
|
|
void* result = axl_memchr(buffer, 0x03, sizeof(buffer));
|
|
|
|
|
ASSERT_NOT_NULL(result);
|
|
|
|
|
ASSERT_TRUE(result == &buffer[3]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KOAN(memchr_returns_null_when_not_found)
|
|
|
|
|
{
|
|
|
|
|
u8 buffer[] = {0x10, 0x20, 0x30, 0x40, 0x50};
|
|
|
|
|
void* result = axl_memchr(buffer, 0x99, sizeof(buffer));
|
|
|
|
|
ASSERT_NULL(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KOAN(memchr_finds_first_occurrence)
|
|
|
|
|
{
|
|
|
|
|
u8 buffer[] = {0xAA, 0xBB, 0xCC, 0xBB, 0xDD};
|
|
|
|
|
void* result = axl_memchr(buffer, 0xBB, sizeof(buffer));
|
|
|
|
|
ASSERT_NOT_NULL(result);
|
2025-12-03 17:37:53 +03:00
|
|
|
ASSERT_TRUE(result == &buffer[1]);
|
2025-12-03 16:49:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KOAN(memchr_finds_at_beginning)
|
|
|
|
|
{
|
|
|
|
|
u8 buffer[] = {0xFF, 0xFE, 0xFD, 0xFC};
|
|
|
|
|
void* result = axl_memchr(buffer, 0xFF, sizeof(buffer));
|
|
|
|
|
ASSERT_NOT_NULL(result);
|
|
|
|
|
ASSERT_TRUE(result == &buffer[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KOAN(memchr_finds_at_end)
|
|
|
|
|
{
|
|
|
|
|
u8 buffer[] = {0x11, 0x22, 0x33, 0x44, 0x55};
|
|
|
|
|
void* result = axl_memchr(buffer, 0x55, sizeof(buffer));
|
|
|
|
|
ASSERT_NOT_NULL(result);
|
|
|
|
|
ASSERT_TRUE(result == &buffer[4]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KOAN(memchr_zero_length_returns_null)
|
|
|
|
|
{
|
|
|
|
|
u8 buffer[] = {0x01, 0x02, 0x03};
|
|
|
|
|
void* result = axl_memchr(buffer, 0x01, 0);
|
|
|
|
|
ASSERT_NULL(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KOAN(memchr_stops_at_specified_length)
|
|
|
|
|
{
|
|
|
|
|
u8 buffer[] = {0x10, 0x20, 0x30, 0x40, 0x50};
|
|
|
|
|
void* result = axl_memchr(buffer, 0x40, 3);
|
|
|
|
|
ASSERT_NULL(result);
|
|
|
|
|
result = axl_memchr(buffer, 0x40, 4);
|
|
|
|
|
ASSERT_NOT_NULL(result);
|
|
|
|
|
ASSERT_TRUE(result == &buffer[3]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KOAN(memchr_handles_all_byte_values)
|
|
|
|
|
{
|
|
|
|
|
u8 buffer[256];
|
2025-12-03 17:37:53 +03:00
|
|
|
for (int i = 0; i < 256; i++)
|
|
|
|
|
{
|
2025-12-03 16:49:54 +03:00
|
|
|
buffer[i] = (u8)i;
|
|
|
|
|
}
|
2025-12-03 17:37:53 +03:00
|
|
|
for (int i = 0; i < 256; i++)
|
|
|
|
|
{
|
2025-12-03 16:49:54 +03:00
|
|
|
void* result = axl_memchr(buffer, (u8)i, sizeof(buffer));
|
|
|
|
|
ASSERT_NOT_NULL(result);
|
|
|
|
|
ASSERT_TRUE(result == &buffer[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KOAN(memchr_matches_standard_memchr)
|
|
|
|
|
{
|
|
|
|
|
u8 buffer[100];
|
2025-12-03 17:37:53 +03:00
|
|
|
for (int i = 0; i < 100; i++)
|
|
|
|
|
{
|
2025-12-03 16:49:54 +03:00
|
|
|
buffer[i] = (u8)(i * 3);
|
|
|
|
|
}
|
2025-12-03 17:37:53 +03:00
|
|
|
for (int val = 0; val < 256; val += 17)
|
|
|
|
|
{
|
2025-12-03 16:49:54 +03:00
|
|
|
void* axl_result = axl_memchr(buffer, (u8)val, sizeof(buffer));
|
|
|
|
|
void* std_result = memchr(buffer, (u8)val, sizeof(buffer));
|
2025-12-03 17:37:53 +03:00
|
|
|
if (std_result == NULL)
|
|
|
|
|
{
|
2025-12-03 16:49:54 +03:00
|
|
|
ASSERT_NULL(axl_result);
|
2025-12-03 17:37:53 +03:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-12-03 16:49:54 +03:00
|
|
|
ASSERT_NOT_NULL(axl_result);
|
|
|
|
|
ASSERT_TRUE(axl_result == std_result);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-12-01 19:39:11 +03:00
|
|
|
|
2025-12-03 17:37:53 +03:00
|
|
|
KOAN(memmove_basic_copy)
|
|
|
|
|
{
|
|
|
|
|
u8 src[64];
|
|
|
|
|
u8 dst[64];
|
|
|
|
|
for (int i = 0; i < 64; i++)
|
|
|
|
|
{
|
|
|
|
|
src[i] = (u8)(i + 1);
|
|
|
|
|
}
|
|
|
|
|
axl_memmove(dst, src, 64);
|
|
|
|
|
for (int i = 0; i < 64; i++)
|
|
|
|
|
{
|
|
|
|
|
ASSERT_INT_EQ(src[i], dst[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KOAN(memmove_zero_bytes_is_nop)
|
|
|
|
|
{
|
|
|
|
|
u8 data[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
|
|
|
|
|
u8 copy[16];
|
|
|
|
|
axl_memcpy(copy, data, 16);
|
|
|
|
|
axl_memmove(copy, NULL, 0);
|
|
|
|
|
for (int i = 0; i < 16; i++)
|
|
|
|
|
{
|
|
|
|
|
ASSERT_INT_EQ(data[i], copy[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KOAN(memmove_overlap_forward)
|
|
|
|
|
{
|
|
|
|
|
u8 buffer[32] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
|
|
|
|
|
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};
|
|
|
|
|
u8 expected[32];
|
|
|
|
|
memcpy(expected, buffer, 32);
|
|
|
|
|
memmove(expected + 8, expected + 4, 16);
|
|
|
|
|
axl_memmove(buffer + 8, buffer + 4, 16);
|
|
|
|
|
for (int i = 0; i < 32; i++)
|
|
|
|
|
{
|
|
|
|
|
ASSERT_INT_EQ(expected[i], buffer[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KOAN(memmove_overlap_backward)
|
|
|
|
|
{
|
|
|
|
|
u8 buffer[32] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
|
|
|
|
|
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};
|
|
|
|
|
u8 expected[32];
|
|
|
|
|
memcpy(expected, buffer, 32);
|
|
|
|
|
memmove(expected + 4, expected + 8, 16);
|
|
|
|
|
axl_memmove(buffer + 4, buffer + 8, 16);
|
|
|
|
|
for (int i = 0; i < 32; i++)
|
|
|
|
|
{
|
|
|
|
|
ASSERT_INT_EQ(expected[i], buffer[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KOAN(memmove_overlap_same_region)
|
|
|
|
|
{
|
|
|
|
|
u8 buffer[32];
|
|
|
|
|
for (int i = 0; i < 32; i++)
|
|
|
|
|
{
|
|
|
|
|
buffer[i] = (u8)i;
|
|
|
|
|
}
|
|
|
|
|
u8 expected[32];
|
|
|
|
|
memcpy(expected, buffer, 32);
|
|
|
|
|
axl_memmove(buffer, buffer, 32);
|
|
|
|
|
for (int i = 0; i < 32; i++)
|
|
|
|
|
{
|
|
|
|
|
ASSERT_INT_EQ(expected[i], buffer[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KOAN(memmove_overlap_single_byte)
|
|
|
|
|
{
|
|
|
|
|
u8 buffer[8] = {0,1,2,3,4,5,6,7};
|
|
|
|
|
u8 expected[8];
|
|
|
|
|
memcpy(expected, buffer, 8);
|
|
|
|
|
memmove(expected + 1, expected, 7);
|
|
|
|
|
axl_memmove(buffer + 1, buffer, 7);
|
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
|
|
|
{
|
|
|
|
|
ASSERT_INT_EQ(expected[i], buffer[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KOAN(memmove_matches_standard_memmove)
|
|
|
|
|
{
|
|
|
|
|
u8 src[128];
|
|
|
|
|
u8 dst_axl[128];
|
|
|
|
|
u8 dst_std[128];
|
|
|
|
|
for (int i = 0; i < 128; i++)
|
|
|
|
|
{
|
|
|
|
|
src[i] = (u8)(i * 7);
|
|
|
|
|
}
|
|
|
|
|
for (int offset = -16; offset <= 16; offset++)
|
|
|
|
|
{
|
|
|
|
|
memcpy(dst_axl, src, 128);
|
|
|
|
|
memcpy(dst_std, src, 128);
|
|
|
|
|
int src_offset = 32;
|
|
|
|
|
int dst_offset = 32 + offset;
|
|
|
|
|
int copy_size = 64;
|
|
|
|
|
axl_memmove(dst_axl + dst_offset, dst_axl + src_offset, copy_size);
|
|
|
|
|
memmove(dst_std + dst_offset, dst_std + src_offset, copy_size);
|
|
|
|
|
for (int i = 0; i < 128; i++)
|
|
|
|
|
{
|
|
|
|
|
ASSERT_INT_EQ(dst_std[i], dst_axl[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KOAN(memmove_small_overlap)
|
|
|
|
|
{
|
|
|
|
|
u8 buffer[10] = {0,1,2,3,4,5,6,7,8,9};
|
|
|
|
|
u8 expected[10];
|
|
|
|
|
memcpy(expected, buffer, 10);
|
|
|
|
|
memmove(expected + 2, expected, 5);
|
|
|
|
|
axl_memmove(buffer + 2, buffer, 5);
|
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
|
|
|
{
|
|
|
|
|
ASSERT_INT_EQ(expected[i], buffer[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KOAN(memmove_large_non_overlap)
|
|
|
|
|
{
|
|
|
|
|
u8 src[256];
|
|
|
|
|
u8 dst[256];
|
|
|
|
|
for (int i = 0; i < 256; i++)
|
|
|
|
|
{
|
|
|
|
|
src[i] = (u8)(255 - i);
|
|
|
|
|
}
|
|
|
|
|
axl_memmove(dst, src, 256);
|
|
|
|
|
for (int i = 0; i < 256; i++)
|
|
|
|
|
{
|
|
|
|
|
ASSERT_INT_EQ(src[i], dst[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-01 19:39:11 +03:00
|
|
|
KOAN(double_free_does_not_crash)
|
|
|
|
|
{
|
|
|
|
|
void* p = axl_malloc(64);
|
|
|
|
|
ASSERT_NOT_NULL(p);
|
|
|
|
|
axl_free(p);
|
2025-12-03 17:37:53 +03:00
|
|
|
axl_free(p);
|
2025-12-01 19:39:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KOAN(large_allocation_near_heap_limit)
|
|
|
|
|
{
|
|
|
|
|
void* p = axl_malloc(AXL_HEAP_SIZE - 1024);
|
2025-12-03 17:37:53 +03:00
|
|
|
ASSERT_NOT_NULL(p);
|
2025-12-01 19:39:11 +03:00
|
|
|
if (p) axl_free(p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KOAN(allocation_of_max_size_fails)
|
|
|
|
|
{
|
|
|
|
|
void* p = axl_malloc(AXL_HEAP_SIZE);
|
|
|
|
|
ASSERT_NULL(p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KOAN(many_small_allocations)
|
|
|
|
|
{
|
|
|
|
|
#define N 1000
|
|
|
|
|
void* ptrs[N];
|
2025-12-03 17:37:53 +03:00
|
|
|
for (int i = 0; i < N; i++)
|
|
|
|
|
{
|
2025-12-01 19:39:11 +03:00
|
|
|
ptrs[i] = axl_malloc(16);
|
|
|
|
|
ASSERT_NOT_NULL(ptrs[i]);
|
|
|
|
|
*(u32*)ptrs[i] = 0xDEADBEEF;
|
|
|
|
|
}
|
2025-12-03 17:37:53 +03:00
|
|
|
for (int i = 0; i < N; i++)
|
|
|
|
|
{
|
2025-12-01 19:39:11 +03:00
|
|
|
ASSERT_INT_EQ(0xDEADBEEF, *(u32*)ptrs[i]);
|
|
|
|
|
axl_free(ptrs[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(void)
|
|
|
|
|
{
|
|
|
|
|
axl_init();
|
|
|
|
|
return koan_run_all();
|
|
|
|
|
}
|