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 <abuf.h>
8 #include <mapmem.h>
9 #include <test/lib.h>
10 #include <test/test.h>
11 #include <test/ut.h>
12 
13 static char test_data[] = "1234";
14 #define TEST_DATA_LEN	sizeof(test_data)
15 #define HUGE_ALLOC_SIZE 0x60000000
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_init_const() */
lib_test_abuf_init_const(struct unit_test_state * uts)51 static int lib_test_abuf_init_const(struct unit_test_state *uts)
52 {
53 	struct abuf buf;
54 	ulong start;
55 	void *ptr;
56 
57 	start = ut_check_free();
58 
59 	ptr = map_sysmem(0x100, 0);
60 
61 	abuf_init_const(&buf, ptr, 10);
62 	ut_asserteq_ptr(ptr, buf.data);
63 	ut_asserteq(10, buf.size);
64 
65 	/* No memory should have been allocated */
66 	ut_assertok(ut_check_delta(start));
67 
68 	return 0;
69 }
70 LIB_TEST(lib_test_abuf_init_const, 0);
71 
72 /* Test abuf_map_sysmem() and abuf_addr() */
lib_test_abuf_map_sysmem(struct unit_test_state * uts)73 static int lib_test_abuf_map_sysmem(struct unit_test_state *uts)
74 {
75 	struct abuf buf;
76 	ulong addr;
77 
78 	abuf_init(&buf);
79 	addr = 0x100;
80 	abuf_map_sysmem(&buf, addr, TEST_DATA_LEN);
81 
82 	ut_asserteq_ptr(map_sysmem(0x100, 0), buf.data);
83 	ut_asserteq(TEST_DATA_LEN, buf.size);
84 	ut_asserteq(false, buf.alloced);
85 
86 	ut_asserteq(addr, abuf_addr(&buf));
87 
88 	return 0;
89 }
90 LIB_TEST(lib_test_abuf_map_sysmem, 0);
91 
92 /* Test abuf_realloc() */
lib_test_abuf_realloc(struct unit_test_state * uts)93 static int lib_test_abuf_realloc(struct unit_test_state *uts)
94 {
95 	struct abuf buf;
96 	ulong start;
97 
98 	start = ut_check_free();
99 
100 	abuf_init(&buf);
101 
102 	/* Allocate an empty buffer */
103 	ut_asserteq(true, abuf_realloc(&buf, 0));
104 	ut_assertnull(buf.data);
105 	ut_asserteq(0, buf.size);
106 	ut_asserteq(false, buf.alloced);
107 
108 	/* Allocate a non-empty abuf */
109 	ut_asserteq(true, abuf_realloc(&buf, TEST_DATA_LEN));
110 	ut_assertnonnull(buf.data);
111 	ut_asserteq(TEST_DATA_LEN, buf.size);
112 	ut_asserteq(true, buf.alloced);
113 
114 	/*
115 	 * Make it smaller.
116 	 */
117 	ut_asserteq(true, abuf_realloc(&buf, TEST_DATA_LEN - 1));
118 	ut_asserteq(TEST_DATA_LEN - 1, buf.size);
119 	ut_asserteq(true, buf.alloced);
120 
121 	/*
122 	 * Make it larger.
123 	 */
124 	ut_asserteq(true, abuf_realloc(&buf, 0x1000));
125 	ut_asserteq(0x1000, buf.size);
126 	ut_asserteq(true, buf.alloced);
127 
128 	/* Free it */
129 	ut_asserteq(true, abuf_realloc(&buf, 0));
130 	ut_assertnull(buf.data);
131 	ut_asserteq(0, buf.size);
132 	ut_asserteq(false, buf.alloced);
133 
134 	/* Check for memory leaks */
135 	ut_assertok(ut_check_delta(start));
136 
137 	return 0;
138 }
139 LIB_TEST(lib_test_abuf_realloc, 0);
140 
141 /* Test abuf_realloc() on an non-allocated buffer of zero size */
lib_test_abuf_realloc_size(struct unit_test_state * uts)142 static int lib_test_abuf_realloc_size(struct unit_test_state *uts)
143 {
144 	struct abuf buf;
145 	ulong start;
146 
147 	start = ut_check_free();
148 
149 	abuf_init(&buf);
150 
151 	/* Allocate some space */
152 	ut_asserteq(true, abuf_realloc(&buf, TEST_DATA_LEN));
153 	ut_assertnonnull(buf.data);
154 	ut_asserteq(TEST_DATA_LEN, buf.size);
155 	ut_asserteq(true, buf.alloced);
156 
157 	/* Free it */
158 	ut_asserteq(true, abuf_realloc(&buf, 0));
159 	ut_assertnull(buf.data);
160 	ut_asserteq(0, buf.size);
161 	ut_asserteq(false, buf.alloced);
162 
163 	/* Check for memory leaks */
164 	ut_assertok(ut_check_delta(start));
165 
166 	return 0;
167 }
168 LIB_TEST(lib_test_abuf_realloc_size, 0);
169 
170 /* Test abuf_realloc_inc() */
lib_test_abuf_realloc_inc(struct unit_test_state * uts)171 static int lib_test_abuf_realloc_inc(struct unit_test_state *uts)
172 {
173 	struct abuf buf;
174 	ulong start;
175 
176 	start = ut_check_free();
177 
178 	abuf_init(&buf);
179 	ut_asserteq(0, buf.size);
180 	ut_asserteq(false, buf.alloced);
181 
182 	abuf_realloc_inc(&buf, 20);
183 	ut_asserteq(20, buf.size);
184 	ut_asserteq(true, buf.alloced);
185 
186 	abuf_uninit(&buf);
187 
188 	/* Check for memory leaks */
189 	ut_assertok(ut_check_delta(start));
190 
191 	return 0;
192 }
193 LIB_TEST(lib_test_abuf_realloc_inc, 0);
194 
195 /* Test handling of buffers that are too large */
lib_test_abuf_large(struct unit_test_state * uts)196 static int lib_test_abuf_large(struct unit_test_state *uts)
197 {
198 	struct abuf buf;
199 	ulong start;
200 	size_t size;
201 	int delta;
202 
203 	start = ut_check_free();
204 
205 	/* Try an impossible size */
206 	abuf_init(&buf);
207 	ut_asserteq(false, abuf_realloc(&buf, HUGE_ALLOC_SIZE));
208 	ut_assertnull(buf.data);
209 	ut_asserteq(0, buf.size);
210 	ut_asserteq(false, buf.alloced);
211 
212 	abuf_uninit(&buf);
213 	ut_assertnull(buf.data);
214 	ut_asserteq(0, buf.size);
215 	ut_asserteq(false, buf.alloced);
216 
217 	/* Start with a normal size then try to increase it, to check realloc */
218 	ut_asserteq(true, abuf_realloc(&buf, TEST_DATA_LEN));
219 	ut_assertnonnull(buf.data);
220 	ut_asserteq(TEST_DATA_LEN, buf.size);
221 	ut_asserteq(true, buf.alloced);
222 	delta = ut_check_delta(start);
223 	ut_assert(delta > 0);
224 
225 	/* try to increase it */
226 	ut_asserteq(false, abuf_realloc(&buf, HUGE_ALLOC_SIZE));
227 	ut_asserteq(TEST_DATA_LEN, buf.size);
228 	ut_asserteq(true, buf.alloced);
229 	ut_asserteq(delta, ut_check_delta(start));
230 
231 	/* Check for memory leaks */
232 	abuf_uninit(&buf);
233 	ut_assertok(ut_check_delta(start));
234 
235 	/* Start with a huge unallocated buf and try to move it */
236 	abuf_init(&buf);
237 	abuf_map_sysmem(&buf, 0, HUGE_ALLOC_SIZE);
238 	ut_asserteq(HUGE_ALLOC_SIZE, buf.size);
239 	ut_asserteq(false, buf.alloced);
240 	ut_assertnull(abuf_uninit_move(&buf, &size));
241 
242 	/* Check for memory leaks */
243 	abuf_uninit(&buf);
244 	ut_assertok(ut_check_delta(start));
245 
246 	return 0;
247 }
248 LIB_TEST(lib_test_abuf_large, 0);
249 
250 /* Test abuf_uninit_move() */
lib_test_abuf_uninit_move(struct unit_test_state * uts)251 static int lib_test_abuf_uninit_move(struct unit_test_state *uts)
252 {
253 	void *ptr, *orig_ptr;
254 	struct abuf buf;
255 	size_t size;
256 	ulong start;
257 	int delta;
258 
259 	start = ut_check_free();
260 
261 	/* Move an empty buffer */
262 	abuf_init(&buf);
263 	ut_assertnull(abuf_uninit_move(&buf, &size));
264 	ut_asserteq(0, size);
265 	ut_assertnull(abuf_uninit_move(&buf, NULL));
266 
267 	/* Move an unallocated buffer */
268 	abuf_set(&buf, test_data, TEST_DATA_LEN);
269 	ut_assertok(ut_check_delta(start));
270 	ptr = abuf_uninit_move(&buf, &size);
271 	ut_asserteq(TEST_DATA_LEN, size);
272 	ut_asserteq_str(ptr, test_data);
273 	ut_assertnonnull(ptr);
274 	ut_assertnull(buf.data);
275 	ut_asserteq(0, buf.size);
276 	ut_asserteq(false, buf.alloced);
277 
278 	/* Check that freeing it frees the only allocation */
279 	delta = ut_check_delta(start);
280 	ut_assert(delta > 0);
281 	free(ptr);
282 	ut_assertok(ut_check_delta(start));
283 
284 	/* Move an allocated buffer */
285 	ut_asserteq(true, abuf_realloc(&buf, TEST_DATA_LEN));
286 	orig_ptr = buf.data;
287 	strcpy(orig_ptr, test_data);
288 
289 	delta = ut_check_delta(start);
290 	ut_assert(delta > 0);
291 	ptr = abuf_uninit_move(&buf, &size);
292 	ut_asserteq(TEST_DATA_LEN, size);
293 	ut_assertnonnull(ptr);
294 	ut_asserteq_ptr(ptr, orig_ptr);
295 	ut_asserteq_str(ptr, test_data);
296 	ut_assertnull(buf.data);
297 	ut_asserteq(0, buf.size);
298 	ut_asserteq(false, buf.alloced);
299 
300 	/* Check there was no new allocation */
301 	ut_asserteq(delta, ut_check_delta(start));
302 
303 	/* Check that freeing it frees the only allocation */
304 	free(ptr);
305 	ut_assertok(ut_check_delta(start));
306 
307 	/* Move an unallocated buffer, without the size */
308 	abuf_set(&buf, test_data, TEST_DATA_LEN);
309 	ut_assertok(ut_check_delta(start));
310 	ptr = abuf_uninit_move(&buf, NULL);
311 	ut_asserteq_str(ptr, test_data);
312 
313 	return 0;
314 }
315 LIB_TEST(lib_test_abuf_uninit_move, 0);
316 
317 /* Test abuf_uninit() */
lib_test_abuf_uninit(struct unit_test_state * uts)318 static int lib_test_abuf_uninit(struct unit_test_state *uts)
319 {
320 	struct abuf buf;
321 
322 	/* Nothing in the buffer */
323 	abuf_init(&buf);
324 	abuf_uninit(&buf);
325 	ut_assertnull(buf.data);
326 	ut_asserteq(0, buf.size);
327 	ut_asserteq(false, buf.alloced);
328 
329 	/* Not allocated */
330 	abuf_set(&buf, test_data, TEST_DATA_LEN);
331 	abuf_uninit(&buf);
332 	ut_assertnull(buf.data);
333 	ut_asserteq(0, buf.size);
334 	ut_asserteq(false, buf.alloced);
335 
336 	return 0;
337 }
338 LIB_TEST(lib_test_abuf_uninit, 0);
339 
340 /* Test abuf_init_set() */
lib_test_abuf_init_set(struct unit_test_state * uts)341 static int lib_test_abuf_init_set(struct unit_test_state *uts)
342 {
343 	struct abuf buf;
344 
345 	abuf_init_set(&buf, test_data, TEST_DATA_LEN);
346 	ut_asserteq_ptr(test_data, buf.data);
347 	ut_asserteq(TEST_DATA_LEN, buf.size);
348 	ut_asserteq(false, buf.alloced);
349 
350 	return 0;
351 }
352 LIB_TEST(lib_test_abuf_init_set, 0);
353 
354 /* Test abuf_init_move() */
lib_test_abuf_init_move(struct unit_test_state * uts)355 static int lib_test_abuf_init_move(struct unit_test_state *uts)
356 {
357 	struct abuf buf;
358 	void *ptr;
359 
360 	ptr = strdup(test_data);
361 	ut_assertnonnull(ptr);
362 
363 	free(ptr);
364 
365 	abuf_init_move(&buf, ptr, TEST_DATA_LEN);
366 	ut_asserteq_ptr(ptr, abuf_data(&buf));
367 	ut_asserteq(TEST_DATA_LEN, abuf_size(&buf));
368 	ut_asserteq(true, buf.alloced);
369 
370 	return 0;
371 }
372 LIB_TEST(lib_test_abuf_init_move, 0);
373 
374 /* Test abuf_init() */
lib_test_abuf_init(struct unit_test_state * uts)375 static int lib_test_abuf_init(struct unit_test_state *uts)
376 {
377 	struct abuf buf;
378 
379 	buf.data = &buf;
380 	buf.size = 123;
381 	buf.alloced = true;
382 	abuf_init(&buf);
383 	ut_assertnull(buf.data);
384 	ut_asserteq(0, buf.size);
385 	ut_asserteq(false, buf.alloced);
386 
387 	return 0;
388 }
389 LIB_TEST(lib_test_abuf_init, 0);
390 
391 /* Test abuf_copy() */
lib_test_abuf_copy(struct unit_test_state * uts)392 static int lib_test_abuf_copy(struct unit_test_state *uts)
393 {
394 	struct abuf buf, copy;
395 	ulong start;
396 
397 	start = ut_check_free();
398 
399 	abuf_init_set(&buf, test_data, TEST_DATA_LEN);
400 	ut_assert(abuf_copy(&buf, &copy));
401 	ut_asserteq(buf.size, copy.size);
402 	ut_assert(buf.data != copy.data);
403 	ut_assert(copy.alloced);
404 	abuf_uninit(&copy);
405 	abuf_uninit(&buf);
406 
407 	/* Check for memory leaks */
408 	ut_assertok(ut_check_delta(start));
409 
410 	return 0;
411 }
412 LIB_TEST(lib_test_abuf_copy, 0);
413 
414 /* Test abuf_init_size() */
lib_test_abuf_init_size(struct unit_test_state * uts)415 static int lib_test_abuf_init_size(struct unit_test_state *uts)
416 {
417 	struct abuf buf;
418 	ulong start;
419 
420 	start = ut_check_free();
421 
422 	ut_assert(abuf_init_size(&buf, TEST_DATA_LEN));
423 	ut_assertnonnull(buf.data);
424 	ut_asserteq(TEST_DATA_LEN, buf.size);
425 	ut_asserteq(true, buf.alloced);
426 	abuf_uninit(&buf);
427 
428 	/* Check for memory leaks */
429 	ut_assertok(ut_check_delta(start));
430 
431 	return 0;
432 }
433 LIB_TEST(lib_test_abuf_init_size, 0);
434 
435 /* Test abuf_printf() */
lib_test_abuf_printf(struct unit_test_state * uts)436 static int lib_test_abuf_printf(struct unit_test_state *uts)
437 {
438 	struct abuf buf, fmt;
439 	ulong start;
440 	char *ptr;
441 
442 	start = ut_check_free();
443 
444 	/* start with a fresh buffer */
445 	abuf_init(&buf);
446 
447 	/* check handling of out-of-memory condition */
448 	malloc_enable_testing(0);
449 	ut_asserteq(-ENOMEM, abuf_printf(&buf, "%s", ""));
450 	malloc_enable_testing(1);
451 
452 	ut_asserteq(0, abuf_printf(&buf, "%s", ""));
453 	ut_asserteq(1, buf.size);
454 	ut_asserteq(true, buf.alloced);
455 	ut_asserteq_str("", buf.data);
456 
457 	/* check expanding it, initially failing */
458 	ut_asserteq(-ENOMEM, abuf_printf(&buf, "%s", "testing"));
459 	malloc_disable_testing();
460 
461 	ut_asserteq(7, abuf_printf(&buf, "%s", "testing"));
462 	ut_asserteq(8, buf.size);
463 	ut_asserteq_str("testing", buf.data);
464 
465 	ut_asserteq(11, abuf_printf(&buf, "testing %d", 123));
466 	ut_asserteq(12, buf.size);
467 	ut_asserteq_str("testing 123", buf.data);
468 
469 	/* make it smaller; buffer should not shrink */
470 	ut_asserteq(9, abuf_printf(&buf, "test %d", 456));
471 	ut_asserteq(12, buf.size);
472 	ut_asserteq_str("test 456", buf.data);
473 
474 	/* test the maximum size */
475 	abuf_init(&fmt);
476 	ut_assert(abuf_realloc(&fmt, 4100));
477 	memset(fmt.data, 'x', 4100);
478 	ptr = fmt.data;
479 	ptr[4096] = '\0';
480 
481 	/* we are allowed up to 4K including the terminator */
482 	ut_asserteq(-E2BIG, abuf_printf(&buf, "%s", ptr));
483 	ptr[4095] = '\0';
484 	ut_asserteq(4095, abuf_printf(&buf, "%s", ptr));
485 
486 	abuf_uninit(&fmt);
487 	abuf_uninit(&buf);
488 
489 	/* Check for memory leaks */
490 	ut_assertok(ut_check_delta(start));
491 
492 	return 0;
493 }
494 LIB_TEST(lib_test_abuf_printf, 0);
495