• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
setup_test(void ** state)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 
teardown_test(void ** state)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. */
fill_buffer_data_range(u8 * buffer,size_t sz,u8 start_value,u8 end_value)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 
test_memmove_full_buffer_copy(void ** state)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 
test_memmove_zero_size(void ** state)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 
test_memmove_buffer_part(void ** state)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 
test_memmove_buffer_part_unaligned(void ** state)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 
test_memmove_copy_to_itself(void ** state)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 
test_memmove_self_higher_to_lower(void ** state)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 
test_memmove_self_higher_to_lower_unaligned(void ** state)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 
test_memmove_self_lower_to_higher(void ** state)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 
test_memmove_self_lower_to_higher_unaligned(void ** state)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 
main(void)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 }
250