1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2021 Google LLC
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6 
7 #include <common.h>
8 #include <abuf.h>
9 #include <mapmem.h>
10 #include <test/lib.h>
11 #include <test/test.h>
12 #include <test/ut.h>
13 
14 static char test_data[] = "1234";
15 #define TEST_DATA_LEN	sizeof(test_data)
16 
17 /* Test abuf_set() */
lib_test_abuf_set(struct unit_test_state * uts)18 static int lib_test_abuf_set(struct unit_test_state *uts)
19 {
20 	struct abuf buf;
21 	ulong start;
22 
23 	start = ut_check_free();
24 
25 	abuf_init(&buf);
26 	abuf_set(&buf, test_data, TEST_DATA_LEN);
27 	ut_asserteq_ptr(test_data, buf.data);
28 	ut_asserteq(TEST_DATA_LEN, buf.size);
29 	ut_asserteq(false, buf.alloced);
30 
31 	/* Force it to allocate */
32 	ut_asserteq(true, abuf_realloc(&buf, TEST_DATA_LEN + 1));
33 	ut_assertnonnull(buf.data);
34 	ut_asserteq(TEST_DATA_LEN + 1, buf.size);
35 	ut_asserteq(true, buf.alloced);
36 
37 	/* Now set it again, to force it to free */
38 	abuf_set(&buf, test_data, TEST_DATA_LEN);
39 	ut_asserteq_ptr(test_data, buf.data);
40 	ut_asserteq(TEST_DATA_LEN, buf.size);
41 	ut_asserteq(false, buf.alloced);
42 
43 	/* Check for memory leaks */
44 	ut_assertok(ut_check_delta(start));
45 
46 	return 0;
47 }
48 LIB_TEST(lib_test_abuf_set, 0);
49 
50 /* Test abuf_map_sysmem() */
lib_test_abuf_map_sysmem(struct unit_test_state * uts)51 static int lib_test_abuf_map_sysmem(struct unit_test_state *uts)
52 {
53 	struct abuf buf;
54 	ulong addr;
55 
56 	abuf_init(&buf);
57 	addr = 0x100;
58 	abuf_map_sysmem(&buf, addr, TEST_DATA_LEN);
59 
60 	ut_asserteq_ptr(map_sysmem(0x100, 0), buf.data);
61 	ut_asserteq(TEST_DATA_LEN, buf.size);
62 	ut_asserteq(false, buf.alloced);
63 
64 	return 0;
65 }
66 LIB_TEST(lib_test_abuf_map_sysmem, 0);
67 
68 /* Test abuf_realloc() */
lib_test_abuf_realloc(struct unit_test_state * uts)69 static int lib_test_abuf_realloc(struct unit_test_state *uts)
70 {
71 	struct abuf buf;
72 	ulong start;
73 	void *ptr;
74 
75 	/*
76 	 * TODO: crashes on sandbox sometimes due to an apparent bug in
77 	 * realloc().
78 	 */
79 	return 0;
80 
81 	start = ut_check_free();
82 
83 	abuf_init(&buf);
84 
85 	/* Allocate an empty buffer */
86 	ut_asserteq(true, abuf_realloc(&buf, 0));
87 	ut_assertnull(buf.data);
88 	ut_asserteq(0, buf.size);
89 	ut_asserteq(false, buf.alloced);
90 
91 	/* Allocate a non-empty abuf */
92 	ut_asserteq(true, abuf_realloc(&buf, TEST_DATA_LEN));
93 	ut_assertnonnull(buf.data);
94 	ut_asserteq(TEST_DATA_LEN, buf.size);
95 	ut_asserteq(true, buf.alloced);
96 	ptr = buf.data;
97 
98 	/*
99 	 * Make it smaller; the pointer should remain the same. Note this relies
100 	 * on knowledge of how U-Boot's realloc() works
101 	 */
102 	ut_asserteq(true, abuf_realloc(&buf, TEST_DATA_LEN - 1));
103 	ut_asserteq(TEST_DATA_LEN - 1, buf.size);
104 	ut_asserteq(true, buf.alloced);
105 	ut_asserteq_ptr(ptr, buf.data);
106 
107 	/*
108 	 * Make it larger, forcing reallocation. Note this relies on knowledge
109 	 * of how U-Boot's realloc() works
110 	 */
111 	ut_asserteq(true, abuf_realloc(&buf, 0x1000));
112 	ut_assert(buf.data != ptr);
113 	ut_asserteq(0x1000, buf.size);
114 	ut_asserteq(true, buf.alloced);
115 
116 	/* Free it */
117 	ut_asserteq(true, abuf_realloc(&buf, 0));
118 	ut_assertnull(buf.data);
119 	ut_asserteq(0, buf.size);
120 	ut_asserteq(false, buf.alloced);
121 
122 	/* Check for memory leaks */
123 	ut_assertok(ut_check_delta(start));
124 
125 	return 0;
126 }
127 LIB_TEST(lib_test_abuf_realloc, 0);
128 
129 /* Test handling of buffers that are too large */
lib_test_abuf_large(struct unit_test_state * uts)130 static int lib_test_abuf_large(struct unit_test_state *uts)
131 {
132 	struct abuf buf;
133 	ulong start;
134 	size_t size;
135 	int delta;
136 	void *ptr;
137 
138 	/*
139 	 * This crashes at present due to trying to allocate more memory than
140 	 * available, which breaks something on sandbox.
141 	 */
142 	return 0;
143 
144 	start = ut_check_free();
145 
146 	/* Try an impossible size */
147 	abuf_init(&buf);
148 	ut_asserteq(false, abuf_realloc(&buf, CONFIG_SYS_MALLOC_LEN));
149 	ut_assertnull(buf.data);
150 	ut_asserteq(0, buf.size);
151 	ut_asserteq(false, buf.alloced);
152 
153 	abuf_uninit(&buf);
154 	ut_assertnull(buf.data);
155 	ut_asserteq(0, buf.size);
156 	ut_asserteq(false, buf.alloced);
157 
158 	/* Start with a normal size then try to increase it, to check realloc */
159 	ut_asserteq(true, abuf_realloc(&buf, TEST_DATA_LEN));
160 	ut_assertnonnull(buf.data);
161 	ut_asserteq(TEST_DATA_LEN, buf.size);
162 	ut_asserteq(true, buf.alloced);
163 	ptr = buf.data;
164 	delta = ut_check_delta(start);
165 	ut_assert(delta > 0);
166 
167 	/* try to increase it */
168 	ut_asserteq(false, abuf_realloc(&buf, CONFIG_SYS_MALLOC_LEN));
169 	ut_asserteq_ptr(ptr, buf.data);
170 	ut_asserteq(TEST_DATA_LEN, buf.size);
171 	ut_asserteq(true, buf.alloced);
172 	ut_asserteq(delta, ut_check_delta(start));
173 
174 	/* Check for memory leaks */
175 	abuf_uninit(&buf);
176 	ut_assertok(ut_check_delta(start));
177 
178 	/* Start with a huge unallocated buf and try to move it */
179 	abuf_init(&buf);
180 	abuf_map_sysmem(&buf, 0, CONFIG_SYS_MALLOC_LEN);
181 	ut_asserteq(CONFIG_SYS_MALLOC_LEN, buf.size);
182 	ut_asserteq(false, buf.alloced);
183 	ut_assertnull(abuf_uninit_move(&buf, &size));
184 
185 	/* Check for memory leaks */
186 	abuf_uninit(&buf);
187 	ut_assertok(ut_check_delta(start));
188 
189 	return 0;
190 }
191 LIB_TEST(lib_test_abuf_large, 0);
192 
193 /* Test abuf_uninit_move() */
lib_test_abuf_uninit_move(struct unit_test_state * uts)194 static int lib_test_abuf_uninit_move(struct unit_test_state *uts)
195 {
196 	void *ptr, *orig_ptr;
197 	struct abuf buf;
198 	size_t size;
199 	ulong start;
200 	int delta;
201 
202 	start = ut_check_free();
203 
204 	/*
205 	 * TODO: crashes on sandbox sometimes due to an apparent bug in
206 	 * realloc().
207 	 */
208 	return 0;
209 
210 	/* Move an empty buffer */
211 	abuf_init(&buf);
212 	ut_assertnull(abuf_uninit_move(&buf, &size));
213 	ut_asserteq(0, size);
214 	ut_assertnull(abuf_uninit_move(&buf, NULL));
215 
216 	/* Move an unallocated buffer */
217 	abuf_set(&buf, test_data, TEST_DATA_LEN);
218 	ut_assertok(ut_check_delta(start));
219 	ptr = abuf_uninit_move(&buf, &size);
220 	ut_asserteq(TEST_DATA_LEN, size);
221 	ut_asserteq_str(ptr, test_data);
222 	ut_assertnonnull(ptr);
223 	ut_assertnull(buf.data);
224 	ut_asserteq(0, buf.size);
225 	ut_asserteq(false, buf.alloced);
226 
227 	/* Check that freeing it frees the only allocation */
228 	delta = ut_check_delta(start);
229 	ut_assert(delta > 0);
230 	free(ptr);
231 	ut_assertok(ut_check_delta(start));
232 
233 	/* Move an allocated buffer */
234 	ut_asserteq(true, abuf_realloc(&buf, TEST_DATA_LEN));
235 	orig_ptr = buf.data;
236 	strcpy(orig_ptr, test_data);
237 
238 	delta = ut_check_delta(start);
239 	ut_assert(delta > 0);
240 	ptr = abuf_uninit_move(&buf, &size);
241 	ut_asserteq(TEST_DATA_LEN, size);
242 	ut_assertnonnull(ptr);
243 	ut_asserteq_ptr(ptr, orig_ptr);
244 	ut_asserteq_str(ptr, test_data);
245 	ut_assertnull(buf.data);
246 	ut_asserteq(0, buf.size);
247 	ut_asserteq(false, buf.alloced);
248 
249 	/* Check there was no new allocation */
250 	ut_asserteq(delta, ut_check_delta(start));
251 
252 	/* Check that freeing it frees the only allocation */
253 	free(ptr);
254 	ut_assertok(ut_check_delta(start));
255 
256 	/* Move an unallocated buffer, without the size */
257 	abuf_set(&buf, test_data, TEST_DATA_LEN);
258 	ut_assertok(ut_check_delta(start));
259 	ptr = abuf_uninit_move(&buf, NULL);
260 	ut_asserteq_str(ptr, test_data);
261 
262 	return 0;
263 }
264 LIB_TEST(lib_test_abuf_uninit_move, 0);
265 
266 /* Test abuf_uninit() */
lib_test_abuf_uninit(struct unit_test_state * uts)267 static int lib_test_abuf_uninit(struct unit_test_state *uts)
268 {
269 	struct abuf buf;
270 
271 	/* Nothing in the buffer */
272 	abuf_init(&buf);
273 	abuf_uninit(&buf);
274 	ut_assertnull(buf.data);
275 	ut_asserteq(0, buf.size);
276 	ut_asserteq(false, buf.alloced);
277 
278 	/* Not allocated */
279 	abuf_set(&buf, test_data, TEST_DATA_LEN);
280 	abuf_uninit(&buf);
281 	ut_assertnull(buf.data);
282 	ut_asserteq(0, buf.size);
283 	ut_asserteq(false, buf.alloced);
284 
285 	return 0;
286 }
287 LIB_TEST(lib_test_abuf_uninit, 0);
288 
289 /* Test abuf_init_set() */
lib_test_abuf_init_set(struct unit_test_state * uts)290 static int lib_test_abuf_init_set(struct unit_test_state *uts)
291 {
292 	struct abuf buf;
293 
294 	abuf_init_set(&buf, test_data, TEST_DATA_LEN);
295 	ut_asserteq_ptr(test_data, buf.data);
296 	ut_asserteq(TEST_DATA_LEN, buf.size);
297 	ut_asserteq(false, buf.alloced);
298 
299 	return 0;
300 }
301 LIB_TEST(lib_test_abuf_init_set, 0);
302 
303 /* Test abuf_init_move() */
lib_test_abuf_init_move(struct unit_test_state * uts)304 static int lib_test_abuf_init_move(struct unit_test_state *uts)
305 {
306 	struct abuf buf;
307 	void *ptr;
308 
309 	/*
310 	 * TODO: crashes on sandbox sometimes due to an apparent bug in
311 	 * realloc().
312 	 */
313 	return 0;
314 
315 	ptr = strdup(test_data);
316 	ut_assertnonnull(ptr);
317 
318 	free(ptr);
319 
320 	abuf_init_move(&buf, ptr, TEST_DATA_LEN);
321 	ut_asserteq_ptr(ptr, abuf_data(&buf));
322 	ut_asserteq(TEST_DATA_LEN, abuf_size(&buf));
323 	ut_asserteq(true, buf.alloced);
324 
325 	return 0;
326 }
327 LIB_TEST(lib_test_abuf_init_move, 0);
328 
329 /* Test abuf_init() */
lib_test_abuf_init(struct unit_test_state * uts)330 static int lib_test_abuf_init(struct unit_test_state *uts)
331 {
332 	struct abuf buf;
333 
334 	buf.data = &buf;
335 	buf.size = 123;
336 	buf.alloced = true;
337 	abuf_init(&buf);
338 	ut_assertnull(buf.data);
339 	ut_asserteq(0, buf.size);
340 	ut_asserteq(false, buf.alloced);
341 
342 	return 0;
343 }
344 LIB_TEST(lib_test_abuf_init, 0);
345