1 /*
2  * Copyright (c) 2020 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <zephyr.h>
7 #include <ztest.h>
8 #include <sys/sys_heap.h>
9 
10 #define HEAP_SZ 0x1000
11 
12 uint8_t __aligned(8) heapmem[HEAP_SZ];
13 
14 /* Heap metadata sizes */
15 uint8_t *heap_start, *heap_end;
16 
17 /* Note that this test is making whitebox assumptions about the
18  * behavior of the heap in order to exercise coverage of the
19  * underlying code: that chunk headers are 8 bytes, that heap chunks
20  * are returned low-adddress to high, and that freed blocks are merged
21  * immediately with adjacent free blocks.
22  */
check_heap_align(struct sys_heap * h,size_t prefix,size_t align,size_t size)23 static void check_heap_align(struct sys_heap *h,
24 			     size_t prefix, size_t align, size_t size)
25 {
26 	void *p, *q, *r, *s;
27 
28 	p = sys_heap_alloc(h, prefix);
29 	zassert_true(prefix == 0 || p != NULL, "prefix allocation failed");
30 
31 	q = sys_heap_aligned_alloc(h, align, size);
32 	zassert_true(q != NULL, "first aligned allocation failed");
33 	zassert_true((((uintptr_t)q) & (align - 1)) == 0, "block not aligned");
34 
35 	r = sys_heap_aligned_alloc(h, align, size);
36 	zassert_true(r != NULL, "second aligned allocation failed");
37 	zassert_true((((uintptr_t)r) & (align - 1)) == 0, "block not aligned");
38 
39 	/* Make sure ALL the split memory goes back into the heap and
40 	 * we can allocate the full remaining suffix
41 	 */
42 	s = sys_heap_alloc(h, (heap_end - (uint8_t *)r) - size - 8);
43 	zassert_true(s != NULL, "suffix allocation failed (%zd/%zd/%zd)",
44 				prefix, align, size);
45 
46 	sys_heap_free(h, p);
47 	sys_heap_free(h, q);
48 	sys_heap_free(h, r);
49 	sys_heap_free(h, s);
50 
51 	/* Make sure it's still valid, and empty */
52 	zassert_true(sys_heap_validate(h), "heap invalid");
53 	p = sys_heap_alloc(h, heap_end - heap_start);
54 	zassert_true(p != NULL, "heap not empty");
55 	q = sys_heap_alloc(h, 1);
56 	zassert_true(q == NULL, "heap not full");
57 	sys_heap_free(h, p);
58 }
59 
test_aligned_alloc(void)60 static void test_aligned_alloc(void)
61 {
62 	struct sys_heap heap = {};
63 	void *p, *q;
64 
65 	sys_heap_init(&heap, heapmem, HEAP_SZ);
66 
67 	p = sys_heap_alloc(&heap, 1);
68 	zassert_true(p != NULL, "initial alloc failed");
69 	sys_heap_free(&heap, p);
70 
71 	/* Heap starts where that first chunk was, and ends one 8-byte
72 	 * chunk header before the end of its memory
73 	 */
74 	heap_start = p;
75 	heap_end = heapmem + HEAP_SZ - 8;
76 
77 	for (size_t align = 8; align < HEAP_SZ / 4; align *= 2) {
78 		for (size_t prefix = 0; prefix <= align; prefix += 8) {
79 			for (size_t size = 8; size <= align; size += 8) {
80 				check_heap_align(&heap, prefix, align, size);
81 			}
82 		}
83 	}
84 
85 	/* corner case on small heaps */
86 	p = sys_heap_aligned_alloc(&heap, 8, 12);
87 	memset(p, 0, 12);
88 	zassert_true(sys_heap_validate(&heap), "heap invalid");
89 	sys_heap_free(&heap, p);
90 
91 	/* corner case with minimizing the overallocation before alignment */
92 	p = sys_heap_aligned_alloc(&heap, 16, 16);
93 	q = sys_heap_aligned_alloc(&heap, 16, 17);
94 	memset(p, 0, 16);
95 	memset(q, 0, 17);
96 	zassert_true(sys_heap_validate(&heap), "heap invalid");
97 	sys_heap_free(&heap, p);
98 	sys_heap_free(&heap, q);
99 }
100 
test_main(void)101 void test_main(void)
102 {
103 	ztest_test_suite(lib_heap_align_test,
104 			 ztest_unit_test(test_aligned_alloc));
105 
106 	ztest_run_test_suite(lib_heap_align_test);
107 }
108