/ tests / lib / malloc-test.c
malloc-test.c
  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  
 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  
 46  static int setup_calloc_test(void **state)
 47  {
 48  	memset(_test_heap, 0xFF, TEST_HEAP_SZ);
 49  	return setup_test(state);
 50  }
 51  
 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  
 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  
 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  
 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  
 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  
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  
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  
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  
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  }