xref: /aosp_15_r20/external/coreboot/tests/lib/malloc-test.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 /* Include malloc() and memalign() source code and alter its name to indicate the functions
4    source origin. */
5 #define calloc cb_calloc
6 #define malloc cb_malloc
7 #define free cb_free
8 #define memalign cb_memalign
9 #undef __noreturn
10 #define __noreturn
11 
12 #include "../lib/malloc.c"
13 
14 #undef calloc
15 #undef malloc
16 #undef free
17 #undef memalign
18 #undef __noreturn
19 #define __noreturn __attribute__((noreturn))
20 
21 #include <stdlib.h>
22 #include <tests/test.h>
23 #include <commonlib/helpers.h>
24 #include <types.h>
25 #include <symbols.h>
26 
27 /* 4 MiB */
28 #define TEST_HEAP_SZ 0x400000
29 
30 /* Heap region setup */
31 __weak extern uint8_t _test_heap[];
32 __weak extern uint8_t _etest_heap[];
33 TEST_REGION(test_heap, TEST_HEAP_SZ);
34 TEST_SYMBOL(_heap, _test_heap);
35 TEST_SYMBOL(_eheap, _etest_heap);
36 
setup_test(void ** state)37 static int setup_test(void **state)
38 {
39 	free_mem_ptr = &_heap;
40 	free_mem_end_ptr = &_eheap;
41 	free_last_alloc_ptr = &_heap;
42 
43 	return 0;
44 }
45 
setup_calloc_test(void ** state)46 static int setup_calloc_test(void **state)
47 {
48 	memset(_test_heap, 0xFF, TEST_HEAP_SZ);
49 	return setup_test(state);
50 }
51 
test_malloc_out_of_memory(void ** state)52 static void test_malloc_out_of_memory(void **state)
53 {
54 	void *ptr = cb_malloc(TEST_HEAP_SZ);
55 	assert_ptr_equal(ptr, NULL);
56 }
57 
test_malloc_zero(void ** state)58 static void test_malloc_zero(void **state)
59 {
60 	void *ptr1 = cb_malloc(0);
61 	void *ptr2 = cb_malloc(0);
62 	void *ptr3 = cb_malloc(0);
63 
64 	/* Expect malloc(0) to return the same pointer as there are no bytes
65 	   to be added to the heap */
66 	assert_ptr_equal(ptr1, ptr2);
67 	assert_ptr_equal(ptr2, ptr3);
68 }
69 
test_malloc_multiple_small_allocations(void ** state)70 static void test_malloc_multiple_small_allocations(void **state)
71 {
72 	/* Make multiple small allocations (smaller than alignment)
73 	   Expect no call to die(), as this allocations should be small
74 	   enough to fit in provided memory */
75 	void *prev;
76 	void *curr = cb_malloc(3);
77 	assert_non_null(curr);
78 	for (int i = 0; i < 1000; ++i) {
79 		prev = curr;
80 		curr = cb_malloc(3);
81 		assert_non_null(curr);
82 		assert_true(prev < curr);
83 	}
84 }
85 
test_memalign_different_alignments(void ** state)86 static void test_memalign_different_alignments(void **state)
87 {
88 	void *ptr1 = cb_memalign(4, 30);
89 	void *ptr2 = cb_memalign(16, 22);
90 	void *ptr3 = cb_memalign(8, 64);
91 
92 	assert_true((uintptr_t)ptr1 % 4 == 0);
93 	assert_true((uintptr_t)ptr2 % 16 == 0);
94 	assert_true((uintptr_t)ptr3 % 8 == 0);
95 }
96 
test_memalign_out_of_memory(void ** state)97 static void test_memalign_out_of_memory(void **state)
98 {
99 	void *ptr = cb_memalign(16, TEST_HEAP_SZ);
100 	assert_ptr_equal(ptr, NULL);
101 }
102 
test_memalign_zero(void ** state)103 static void test_memalign_zero(void **state)
104 {
105 	void *ptr1 = cb_memalign(16, 0);
106 	void *ptr2 = cb_memalign(7, 0);
107 	void *ptr3 = cb_memalign(11, 0);
108 
109 	/* Expect memalign(x, 0) to return the same pointer as there are no bytes
110 	   to be added to the heap */
111 	assert_ptr_equal(ptr1, ptr2);
112 	assert_ptr_equal(ptr2, ptr3);
113 }
114 
test_memalign_multiple_small_allocations(void ** state)115 static void test_memalign_multiple_small_allocations(void **state)
116 {
117 	/* Make multiple small allocations (smaller than alignment)
118 	   Expect no call to die(), as this allocations should be small
119 	   enough to fit in provided memory. There should also be no error
120 	   when allocating memory with different align values. */
121 	void *prev;
122 	void *curr = cb_memalign(3, 3);
123 	assert_non_null(curr);
124 	for (int i = 0; i < 1000; ++i) {
125 		/* Expect new pointer larger than previously allocated and aligned to provided
126 		   value. Alignment has to be power of 2 to be applied correctly. */
127 		prev = curr;
128 		curr = cb_memalign(2u << (i % 6), 3);
129 		assert_non_null(curr);
130 		assert_true(prev < curr);
131 		assert_true((uintptr_t)curr % (2u << (i % 6)) == 0);
132 	}
133 }
134 
test_calloc_memory_is_zeroed(void ** state)135 static void test_calloc_memory_is_zeroed(void **state)
136 {
137 	const size_t nitems = 42;
138 	const size_t size = sizeof(uint32_t);
139 	void *ptr = cb_calloc(nitems, size);
140 	assert_non_null(ptr);
141 
142 	for (size_t i = 0; i < nitems; i++) {
143 		const uint32_t *p = (const uint32_t *)ptr + i;
144 		assert_int_equal(*p, 0);
145 	}
146 }
147 
main(void)148 int main(void)
149 {
150 	const struct CMUnitTest tests[] = {
151 		cmocka_unit_test_setup(test_malloc_out_of_memory, setup_test),
152 		cmocka_unit_test_setup(test_malloc_zero, setup_test),
153 		cmocka_unit_test_setup(test_malloc_multiple_small_allocations, setup_test),
154 		cmocka_unit_test_setup(test_memalign_different_alignments, setup_test),
155 		cmocka_unit_test_setup(test_memalign_out_of_memory, setup_test),
156 		cmocka_unit_test_setup(test_memalign_zero, setup_test),
157 		cmocka_unit_test_setup(test_memalign_multiple_small_allocations, setup_test),
158 		cmocka_unit_test_setup(test_calloc_memory_is_zeroed, setup_calloc_test),
159 	};
160 
161 	return cb_run_group_tests(tests, NULL, NULL);
162 }
163