memmove-test.c
1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 3 #define memmove cb_memmove 4 #include "../lib/memmove.c" 5 #undef memmove 6 7 #include <stdlib.h> 8 #include <tests/test.h> 9 #include <commonlib/helpers.h> 10 #include <types.h> 11 12 #define MEMMOVE_BUFFER_SZ (4 * KiB) 13 14 /* Prototype of memmove() from string.h was changed to cb_memmove(). 15 It has to be defined again. */ 16 void *memmove(void *dst, const void *src, size_t n); 17 18 struct test_memmove_data { 19 u8 *buffer_from; 20 u8 *buffer_to; 21 u8 *helper_buffer; 22 }; 23 24 int setup_test(void **state) 25 { 26 struct test_memmove_data *s = malloc(sizeof(struct test_memmove_data)); 27 28 if (!s) 29 return -1; 30 31 s->buffer_from = malloc(MEMMOVE_BUFFER_SZ); 32 s->buffer_to = malloc(MEMMOVE_BUFFER_SZ); 33 s->helper_buffer = malloc(MEMMOVE_BUFFER_SZ); 34 35 if (!s->buffer_from || !s->buffer_to || !s->helper_buffer) { 36 free(s->buffer_from); 37 free(s->buffer_to); 38 free(s->helper_buffer); 39 free(s); 40 return -1; 41 } 42 43 /* Fill buffers with different values (other than zero) to make them distinguishable. 44 The helper buffer is often used as a backup of destination buffer so it has the 45 same value. */ 46 memset(s->buffer_from, 0xAB, MEMMOVE_BUFFER_SZ); 47 memset(s->buffer_to, 0xBC, MEMMOVE_BUFFER_SZ); 48 memset(s->helper_buffer, 0xBC, MEMMOVE_BUFFER_SZ); 49 50 *state = s; 51 52 return 0; 53 } 54 55 int teardown_test(void **state) 56 { 57 struct test_memmove_data *s = *state; 58 59 free(s->buffer_from); 60 free(s->buffer_to); 61 free(s->helper_buffer); 62 free(s); 63 64 return 0; 65 } 66 67 /* Fill buffer with values from provided range [start; end] in circular way. */ 68 static void fill_buffer_data_range(u8 *buffer, size_t sz, u8 start_value, u8 end_value) 69 { 70 for (size_t i = 0; i < sz; ++i) 71 buffer[i] = (start_value + i) % (end_value - start_value + 1); 72 } 73 74 static void test_memmove_full_buffer_copy(void **state) 75 { 76 struct test_memmove_data *s = *state; 77 void *res_cb; 78 79 fill_buffer_data_range(s->buffer_from, MEMMOVE_BUFFER_SZ, 0, 255); 80 81 res_cb = cb_memmove(s->buffer_to, s->buffer_from, MEMMOVE_BUFFER_SZ); 82 83 assert_ptr_equal(s->buffer_to, res_cb); 84 assert_memory_equal(s->buffer_from, s->buffer_to, MEMMOVE_BUFFER_SZ); 85 } 86 87 static void test_memmove_zero_size(void **state) 88 { 89 struct test_memmove_data *s = *state; 90 void *res_cb; 91 92 fill_buffer_data_range(s->buffer_from, MEMMOVE_BUFFER_SZ, 'A', 'Z'); 93 94 /* Expect no change in destination buffer. */ 95 res_cb = cb_memmove(s->buffer_to, s->buffer_from, 0); 96 assert_ptr_equal(res_cb, s->buffer_to); 97 assert_memory_equal(s->buffer_to, s->helper_buffer, MEMMOVE_BUFFER_SZ); 98 } 99 100 static void test_memmove_buffer_part(void **state) 101 { 102 struct test_memmove_data *s = *state; 103 void *res_cb; 104 const size_t offset = MEMMOVE_BUFFER_SZ / 4; 105 const size_t sz = MEMMOVE_BUFFER_SZ / 3; 106 107 /* Self-test for correct data ranges */ 108 assert_true(offset + sz <= MEMMOVE_BUFFER_SZ); 109 110 fill_buffer_data_range(s->buffer_from, MEMMOVE_BUFFER_SZ, '0', '9'); 111 112 /* Expect only *sz* bytes of buffer to be copied. Helper buffer is used as template. */ 113 res_cb = cb_memmove(s->buffer_to + offset, s->buffer_from, sz); 114 assert_ptr_equal(s->buffer_to + offset, res_cb); 115 assert_memory_equal(s->buffer_to, s->helper_buffer, offset); 116 assert_memory_equal(s->buffer_to + offset, s->buffer_from, sz); 117 assert_memory_equal(s->buffer_to + offset + sz, s->helper_buffer + offset + sz, 118 MEMMOVE_BUFFER_SZ - (offset + sz)); 119 } 120 121 static void test_memmove_buffer_part_unaligned(void **state) 122 { 123 struct test_memmove_data *s = *state; 124 void *res_cb; 125 const size_t dst_offset = MEMMOVE_BUFFER_SZ / 8 + 3; 126 const size_t src_offset = MEMMOVE_BUFFER_SZ / 4 - 3; 127 const size_t sz = MEMMOVE_BUFFER_SZ / 4 + 7; 128 129 /* Self-test for correct data ranges */ 130 assert_true(dst_offset + sz <= MEMMOVE_BUFFER_SZ); 131 assert_true(src_offset + sz <= MEMMOVE_BUFFER_SZ); 132 133 fill_buffer_data_range(s->buffer_from, MEMMOVE_BUFFER_SZ, 0x13, 0xB7); 134 135 res_cb = cb_memmove(s->buffer_to + dst_offset, s->buffer_from + src_offset, sz); 136 assert_ptr_equal(s->buffer_to + dst_offset, res_cb); 137 assert_memory_equal(s->buffer_to, s->helper_buffer, dst_offset); 138 assert_memory_equal(s->buffer_to + dst_offset, s->buffer_from + src_offset, sz); 139 assert_memory_equal(s->buffer_to + dst_offset + sz, s->helper_buffer + dst_offset + sz, 140 MEMMOVE_BUFFER_SZ - (dst_offset + sz)); 141 } 142 143 static void test_memmove_copy_to_itself(void **state) 144 { 145 struct test_memmove_data *s = *state; 146 void *res_cb; 147 148 fill_buffer_data_range(s->buffer_to, MEMMOVE_BUFFER_SZ, 'G', 'X'); 149 memmove(s->buffer_to, s->helper_buffer, MEMMOVE_BUFFER_SZ); 150 151 /* Expect no change in source/destination buffer. */ 152 res_cb = cb_memmove(s->buffer_to, s->buffer_to, MEMMOVE_BUFFER_SZ); 153 assert_ptr_equal(res_cb, s->buffer_to); 154 assert_memory_equal(s->buffer_to, s->helper_buffer, MEMMOVE_BUFFER_SZ); 155 } 156 157 static void test_memmove_self_higher_to_lower(void **state) 158 { 159 struct test_memmove_data *s = *state; 160 void *res_cb; 161 const size_t offset = MEMMOVE_BUFFER_SZ / 8; 162 const size_t sz = MEMMOVE_BUFFER_SZ - offset; 163 164 fill_buffer_data_range(s->buffer_to, MEMMOVE_BUFFER_SZ, 'd', 'v'); 165 memmove(s->helper_buffer, s->buffer_to, MEMMOVE_BUFFER_SZ); 166 167 /* Expect only *sz* bytes to be overwritten and *offset* bytes to be left at the end. */ 168 res_cb = cb_memmove(s->buffer_to, s->buffer_to + offset, sz); 169 assert_ptr_equal(res_cb, s->buffer_to); 170 assert_memory_equal(s->buffer_to, s->helper_buffer + offset, sz); 171 assert_memory_equal(s->buffer_to + sz, s->helper_buffer + sz, offset); 172 } 173 174 static void test_memmove_self_higher_to_lower_unaligned(void **state) 175 { 176 struct test_memmove_data *s = *state; 177 void *res_cb; 178 const size_t offset = MEMMOVE_BUFFER_SZ / 6 + 7; 179 const size_t sz = MEMMOVE_BUFFER_SZ - offset; 180 181 fill_buffer_data_range(s->buffer_to, MEMMOVE_BUFFER_SZ, 'd', 'v'); 182 memmove(s->helper_buffer, s->buffer_to, MEMMOVE_BUFFER_SZ); 183 184 /* Expect only *sz* bytes to be overwritten and *offset* bytes to be left at the end. */ 185 res_cb = cb_memmove(s->buffer_to, s->buffer_to + offset, sz); 186 assert_ptr_equal(res_cb, s->buffer_to); 187 assert_memory_equal(s->buffer_to, s->helper_buffer + offset, sz); 188 assert_memory_equal(s->buffer_to + sz, s->helper_buffer + sz, offset); 189 } 190 191 static void test_memmove_self_lower_to_higher(void **state) 192 { 193 struct test_memmove_data *s = *state; 194 void *res_cb; 195 const size_t offset = MEMMOVE_BUFFER_SZ / 4; 196 const size_t sz = MEMMOVE_BUFFER_SZ - offset; 197 198 fill_buffer_data_range(s->buffer_to, MEMMOVE_BUFFER_SZ, 'd', 'v'); 199 memmove(s->helper_buffer, s->buffer_to, MEMMOVE_BUFFER_SZ); 200 201 /* Expect only *sz* bytes to be overwritten and *offset* bytes to be left at the end. */ 202 res_cb = cb_memmove(s->buffer_to + offset, s->buffer_to, sz); 203 assert_ptr_equal(res_cb, s->buffer_to + offset); 204 assert_memory_equal(s->buffer_to + offset, s->helper_buffer, sz); 205 assert_memory_equal(s->buffer_to, s->helper_buffer, offset); 206 } 207 208 static void test_memmove_self_lower_to_higher_unaligned(void **state) 209 { 210 struct test_memmove_data *s = *state; 211 void *res_cb; 212 const size_t offset = MEMMOVE_BUFFER_SZ / 4 - 17; 213 const size_t sz = MEMMOVE_BUFFER_SZ - offset; 214 215 fill_buffer_data_range(s->buffer_to, MEMMOVE_BUFFER_SZ, 'd', 'v'); 216 memmove(s->helper_buffer, s->buffer_to, MEMMOVE_BUFFER_SZ); 217 218 /* Expect only *sz* bytes to be overwritten and *offset* bytes to be left at the end. */ 219 res_cb = cb_memmove(s->buffer_to + offset, s->buffer_to, sz); 220 assert_ptr_equal(res_cb, s->buffer_to + offset); 221 assert_memory_equal(s->buffer_to + offset, s->helper_buffer, sz); 222 assert_memory_equal(s->buffer_to, s->helper_buffer, offset); 223 } 224 225 int main(void) 226 { 227 const struct CMUnitTest tests[] = { 228 cmocka_unit_test_setup_teardown(test_memmove_full_buffer_copy, setup_test, 229 teardown_test), 230 cmocka_unit_test_setup_teardown(test_memmove_zero_size, setup_test, 231 teardown_test), 232 cmocka_unit_test_setup_teardown(test_memmove_buffer_part, setup_test, 233 teardown_test), 234 cmocka_unit_test_setup_teardown(test_memmove_buffer_part_unaligned, setup_test, 235 teardown_test), 236 cmocka_unit_test_setup_teardown(test_memmove_copy_to_itself, setup_test, 237 teardown_test), 238 cmocka_unit_test_setup_teardown(test_memmove_self_higher_to_lower, setup_test, 239 teardown_test), 240 cmocka_unit_test_setup_teardown(test_memmove_self_higher_to_lower_unaligned, 241 setup_test, teardown_test), 242 cmocka_unit_test_setup_teardown(test_memmove_self_lower_to_higher, setup_test, 243 teardown_test), 244 cmocka_unit_test_setup_teardown(test_memmove_self_lower_to_higher_unaligned, 245 setup_test, teardown_test), 246 }; 247 248 return cb_run_group_tests(tests, NULL, NULL); 249 }