/ tests / lib / memmove-test.c
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  }