147 lines
3.8 KiB
C
147 lines
3.8 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
|
|
/* Include malloc() and memalign() source code and alter its name to indicate the functions
|
|
source origin. */
|
|
#define malloc cb_malloc
|
|
#define free cb_free
|
|
#define memalign cb_memalign
|
|
#undef __noreturn
|
|
#define __noreturn
|
|
|
|
#include "../lib/malloc.c"
|
|
|
|
#undef malloc
|
|
#undef free
|
|
#undef memalign
|
|
#undef __noreturn
|
|
#define __noreturn __attribute__((noreturn))
|
|
|
|
#include <stdlib.h>
|
|
#include <tests/test.h>
|
|
#include <commonlib/helpers.h>
|
|
#include <types.h>
|
|
#include <symbols.h>
|
|
|
|
/* 4 MiB */
|
|
#define TEST_HEAP_SZ 0x400000
|
|
|
|
/* Heap region setup */
|
|
__weak extern uint8_t _test_heap[];
|
|
__weak extern uint8_t _etest_heap[];
|
|
TEST_REGION(test_heap, TEST_HEAP_SZ);
|
|
TEST_SYMBOL(_heap, _test_heap);
|
|
TEST_SYMBOL(_eheap, _etest_heap);
|
|
|
|
void die(const char *msg, ...)
|
|
{
|
|
function_called();
|
|
}
|
|
|
|
static int setup_test(void **state)
|
|
{
|
|
free_mem_ptr = &_heap;
|
|
free_mem_end_ptr = &_eheap;
|
|
free_last_alloc_ptr = &_heap;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void test_malloc_out_of_memory(void **state)
|
|
{
|
|
/* Expect die() call if out of memory */
|
|
expect_function_call(die);
|
|
cb_malloc(TEST_HEAP_SZ);
|
|
}
|
|
|
|
static void test_malloc_zero(void **state)
|
|
{
|
|
void *ptr1 = cb_malloc(0);
|
|
void *ptr2 = cb_malloc(0);
|
|
void *ptr3 = cb_malloc(0);
|
|
|
|
/* Expect malloc(0) to return the same pointer as there are no bytes
|
|
to be added to the heap */
|
|
assert_ptr_equal(ptr1, ptr2);
|
|
assert_ptr_equal(ptr2, ptr3);
|
|
}
|
|
|
|
static void test_malloc_multiple_small_allocations(void **state)
|
|
{
|
|
/* Make multiple small allocations (smaller than alignment)
|
|
Expect no call to die(), as this allocations should be small
|
|
enough to fit in provided memory */
|
|
void *prev;
|
|
void *curr = cb_malloc(3);
|
|
assert_non_null(curr);
|
|
for (int i = 0; i < 1000; ++i) {
|
|
prev = curr;
|
|
curr = cb_malloc(3);
|
|
assert_non_null(curr);
|
|
assert_true(prev < curr);
|
|
}
|
|
}
|
|
|
|
static void test_memalign_different_alignments(void **state)
|
|
{
|
|
void *ptr1 = cb_memalign(4, 30);
|
|
void *ptr2 = cb_memalign(16, 22);
|
|
void *ptr3 = cb_memalign(8, 64);
|
|
|
|
assert_true((uintptr_t)ptr1 % 4 == 0);
|
|
assert_true((uintptr_t)ptr2 % 16 == 0);
|
|
assert_true((uintptr_t)ptr3 % 8 == 0);
|
|
}
|
|
|
|
static void test_memalign_out_of_memory(void **state)
|
|
{
|
|
expect_function_call(die);
|
|
cb_memalign(16, TEST_HEAP_SZ);
|
|
}
|
|
|
|
static void test_memalign_zero(void **state)
|
|
{
|
|
void *ptr1 = cb_memalign(16, 0);
|
|
void *ptr2 = cb_memalign(7, 0);
|
|
void *ptr3 = cb_memalign(11, 0);
|
|
|
|
/* Expect memalign(x, 0) to return the same pointer as there are no bytes
|
|
to be added to the heap */
|
|
assert_ptr_equal(ptr1, ptr2);
|
|
assert_ptr_equal(ptr2, ptr3);
|
|
}
|
|
|
|
static void test_memalign_multiple_small_allocations(void **state)
|
|
{
|
|
/* Make multiple small allocations (smaller than alignment)
|
|
Expect no call to die(), as this allocations should be small
|
|
enough to fit in provided memory. There should also be no error
|
|
when allocating memory with different align values. */
|
|
void *prev;
|
|
void *curr = cb_memalign(3, 3);
|
|
assert_non_null(curr);
|
|
for (int i = 0; i < 1000; ++i) {
|
|
/* Expect new pointer larger than previously allocated and aligned to provided
|
|
value. Alignment has to be power of 2 to be applied correctly. */
|
|
prev = curr;
|
|
curr = cb_memalign(2u << (i % 6), 3);
|
|
assert_non_null(curr);
|
|
assert_true(prev < curr);
|
|
assert_true((uintptr_t)curr % (2u << (i % 6)) == 0);
|
|
}
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
const struct CMUnitTest tests[] = {
|
|
cmocka_unit_test_setup(test_malloc_out_of_memory, setup_test),
|
|
cmocka_unit_test_setup(test_malloc_zero, setup_test),
|
|
cmocka_unit_test_setup(test_malloc_multiple_small_allocations, setup_test),
|
|
cmocka_unit_test_setup(test_memalign_different_alignments, setup_test),
|
|
cmocka_unit_test_setup(test_memalign_out_of_memory, setup_test),
|
|
cmocka_unit_test_setup(test_memalign_zero, setup_test),
|
|
cmocka_unit_test_setup(test_memalign_multiple_small_allocations, setup_test),
|
|
};
|
|
|
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
|
}
|