diff --git a/axl_memory.c b/axl_memory.c index b73a9e3..723a7ec 100644 --- a/axl_memory.c +++ b/axl_memory.c @@ -254,6 +254,37 @@ void* axl_memchr(const void* ptr, u8 value, u32 n) return NULL; } +void* axl_memmove(void* dst, const void* src, u32 n) +{ + if(!dst || !src || !n) + { + return dst; + } + + const u8* s = (const u8*)src; + u8* d = (u8*)dst; + + if(d > s) + { + s += n - 1; + d += n - 1; + + while(n--) + { + *d-- = *s--; + } + } + else + { + while(n--) + { + *d++ = *s++; + } + } + + return dst; +} + void axl_free(void* ptr) { if(!ptr) diff --git a/axl_memory.h b/axl_memory.h index 2ca24b4..7def2c3 100644 --- a/axl_memory.h +++ b/axl_memory.h @@ -14,6 +14,7 @@ void* axl_memset(void* ptr, i8 c, u32 n); void* axl_memcpy(void* dst, const void* src, u32 count); i32 axl_memcmp(const void* s1, const void* s2, u32 n); void* axl_memchr(const void* ptr, u8 value, u32 n); +void* axl_memmove(void* dst, const void* src, u32 n); void axl_free(void* ptr); #endif diff --git a/axl_memory_test.c b/axl_memory_test.c index 27369ab..e3781b4 100644 --- a/axl_memory_test.c +++ b/axl_memory_test.c @@ -1,7 +1,6 @@ /* * axl_memory_tests.c — Comprehensive unit tests for axl_memory.h */ - #include "axl_memory.h" #include "axl_koan.h" #include @@ -26,7 +25,7 @@ KOAN(malloc_returns_different_pointers) KOAN(malloc_exhaustion_returns_null) { - void* p = axl_malloc(AXL_HEAP_SIZE + 4096); + void* p = axl_malloc(AXL_HEAP_SIZE + 4096); ASSERT_NULL(p); } @@ -44,7 +43,6 @@ KOAN(realloc_zero_size_frees_and_returns_null_or_valid) ASSERT_NOT_NULL(p); void* q = axl_realloc(p, 0); if (q != NULL) axl_free(q); - } KOAN(realloc_enlarge_preserves_content) @@ -72,10 +70,8 @@ KOAN(realloc_shrink_preserves_prefix) 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); } @@ -92,7 +88,7 @@ KOAN(memset_zero_bytes_is_nop) { void* p = axl_malloc(16); axl_memset(p, 0xFF, 16); - axl_memset(p, 0x00, 0); + axl_memset(p, 0x00, 0); for (int i = 0; i < 16; i++) ASSERT_INT_EQ(0xFF, ((u8*)p)[i]); axl_free(p); @@ -113,7 +109,7 @@ 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); + axl_memcpy(p, "junk", 0); ASSERT_INT_EQ(0, memcmp(p, data, 16)); axl_free(p); } @@ -123,7 +119,6 @@ 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); @@ -160,7 +155,7 @@ KOAN(memchr_finds_first_occurrence) u8 buffer[] = {0xAA, 0xBB, 0xCC, 0xBB, 0xDD}; void* result = axl_memchr(buffer, 0xBB, sizeof(buffer)); ASSERT_NOT_NULL(result); - ASSERT_TRUE(result == &buffer[1]); + ASSERT_TRUE(result == &buffer[1]); } KOAN(memchr_finds_at_beginning) @@ -189,11 +184,8 @@ KOAN(memchr_zero_length_returns_null) 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]); @@ -202,12 +194,12 @@ KOAN(memchr_stops_at_specified_length) KOAN(memchr_handles_all_byte_values) { u8 buffer[256]; - for (int i = 0; i < 256; i++) { + for (int i = 0; i < 256; i++) + { buffer[i] = (u8)i; } - - - for (int i = 0; i < 256; i++) { + for (int i = 0; i < 256; i++) + { void* result = axl_memchr(buffer, (u8)i, sizeof(buffer)); ASSERT_NOT_NULL(result); ASSERT_TRUE(result == &buffer[i]); @@ -217,38 +209,175 @@ KOAN(memchr_handles_all_byte_values) KOAN(memchr_matches_standard_memchr) { u8 buffer[100]; - for (int i = 0; i < 100; i++) { + for (int i = 0; i < 100; i++) + { buffer[i] = (u8)(i * 3); } - - - for (int val = 0; val < 256; val += 17) { + for (int val = 0; val < 256; val += 17) + { void* axl_result = axl_memchr(buffer, (u8)val, sizeof(buffer)); void* std_result = memchr(buffer, (u8)val, sizeof(buffer)); - - - if (std_result == NULL) { + if (std_result == NULL) + { ASSERT_NULL(axl_result); - } else { + } + else + { ASSERT_NOT_NULL(axl_result); ASSERT_TRUE(axl_result == std_result); } } } +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]); + } +} + KOAN(double_free_does_not_crash) { void* p = axl_malloc(64); ASSERT_NOT_NULL(p); axl_free(p); - axl_free(p); + axl_free(p); } KOAN(large_allocation_near_heap_limit) { - void* p = axl_malloc(AXL_HEAP_SIZE - 1024); - ASSERT_NOT_NULL(p); + ASSERT_NOT_NULL(p); if (p) axl_free(p); } @@ -262,12 +391,14 @@ KOAN(many_small_allocations) { #define N 1000 void* ptrs[N]; - for (int i = 0; i < N; i++) { + 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++) { + for (int i = 0; i < N; i++) + { ASSERT_INT_EQ(0xDEADBEEF, *(u32*)ptrs[i]); axl_free(ptrs[i]); }