diff --git a/components/heap/test_multi_heap_host/test_multi_heap.cpp b/components/heap/test_multi_heap_host/test_multi_heap.cpp index c3cac1cad1..a892681c7f 100644 --- a/components/heap/test_multi_heap_host/test_multi_heap.cpp +++ b/components/heap/test_multi_heap_host/test_multi_heap.cpp @@ -2,12 +2,30 @@ #include "multi_heap.h" #include "../multi_heap_config.h" +#include "../tlsf/tlsf.h" #include "../tlsf/tlsf_common.h" #include "../tlsf/tlsf_block_functions.h" #include #include +/* The functions __malloc__ and __free__ are used to call the libc + * malloc and free and allocate memory from the host heap. Since the test + * `TEST_CASE("multi_heap many random allocations", "[multi_heap]")` + * calls multi_heap_allocation_impl() with sizes that can go up to 8MB, + * an allocatation on the heap will be prefered rather than the stack which + * might not have the necessary memory. + */ +static void *__malloc__(size_t bytes) +{ + return malloc(bytes); +} + +static void __free__(void *ptr) +{ + free(ptr); +} + /* Insurance against accidentally using libc heap functions in tests */ #undef free #define free #error @@ -61,10 +79,11 @@ TEST_CASE("multi_heap simple allocations", "[multi_heap]") TEST_CASE("multi_heap fragmentation", "[multi_heap]") { - uint8_t small_heap[4 * 1024]; + const size_t HEAP_SIZE = 4 * 1024; + uint8_t small_heap[HEAP_SIZE]; multi_heap_handle_t heap = multi_heap_register(small_heap, sizeof(small_heap)); - const size_t alloc_size = 128; + const size_t alloc_size = 500; void *p[4]; for (int i = 0; i < 4; i++) { @@ -204,20 +223,22 @@ TEST_CASE("multi_heap defrag realloc", "[multi_heap]") #endif -TEST_CASE("multi_heap many random allocations", "[multi_heap]") +void multi_heap_allocation_impl(int heap_size) { - uint8_t big_heap[8 * 1024]; + uint8_t *big_heap = (uint8_t *) __malloc__(heap_size); const int NUM_POINTERS = 64; - printf("Running multi-allocation test...\n"); + printf("Running multi-allocation test with heap_size %d...\n", heap_size); + + REQUIRE( big_heap ); + multi_heap_handle_t heap = multi_heap_register(big_heap, heap_size); void *p[NUM_POINTERS] = { 0 }; size_t s[NUM_POINTERS] = { 0 }; - multi_heap_handle_t heap = multi_heap_register(big_heap, sizeof(big_heap)); const size_t initial_free = multi_heap_free_size(heap); - const int ITERATIONS = 10000; + const int ITERATIONS = 5000; for (int i = 0; i < ITERATIONS; i++) { /* check all pointers allocated so far are valid inside big_heap */ @@ -228,11 +249,11 @@ TEST_CASE("multi_heap many random allocations", "[multi_heap]") uint8_t n = rand() % NUM_POINTERS; - if (rand() % 4 == 0) { + if (i % 4 == 0) { /* 1 in 4 iterations, try to realloc the buffer instead of using malloc/free */ - size_t new_size = rand() % 1024; + size_t new_size = (rand() % 1023) + 1; void *new_p = multi_heap_realloc(heap, p[n], new_size); printf("realloc %p -> %p (%zu -> %zu)\n", p[n], new_p, s[n], new_size); multi_heap_check(heap, true); @@ -241,13 +262,12 @@ TEST_CASE("multi_heap many random allocations", "[multi_heap]") s[n] = new_size; if (new_size > 0) { REQUIRE( p[n] >= big_heap ); - REQUIRE( p[n] < big_heap + sizeof(big_heap) ); + REQUIRE( p[n] < big_heap + heap_size ); memset(p[n], n, new_size); } } continue; } - if (p[n] != NULL) { if (s[n] > 0) { /* Verify pre-existing contents of p[n] */ @@ -271,14 +291,13 @@ TEST_CASE("multi_heap many random allocations", "[multi_heap]") printf("malloc %p (%zu)\n", p[n], s[n]); if (p[n] != NULL) { REQUIRE( p[n] >= big_heap ); - REQUIRE( p[n] < big_heap + sizeof(big_heap) ); + REQUIRE( p[n] < big_heap + heap_size ); } if (!multi_heap_check(heap, true)) { printf("FAILED iteration %d after mallocing %p (%zu bytes)\n", i, p[n], s[n]); multi_heap_dump(heap); REQUIRE(0); } - if (p[n] != NULL) { memset(p[n], n, s[n]); } @@ -294,6 +313,15 @@ TEST_CASE("multi_heap many random allocations", "[multi_heap]") } REQUIRE( initial_free == multi_heap_free_size(heap) ); + __free__(big_heap); +} + +TEST_CASE("multi_heap many random allocations", "[multi_heap]") +{ + size_t poolsize[] = { 15, 255, 4095, 8191 }; + for (size_t i = 0; i < sizeof(poolsize)/sizeof(size_t); i++) { + multi_heap_allocation_impl(poolsize[i] * 1024); + } } TEST_CASE("multi_heap_get_info() function", "[multi_heap]") @@ -393,8 +421,9 @@ TEST_CASE("multi_heap minimum-size allocations", "[multi_heap]") TEST_CASE("multi_heap_realloc()", "[multi_heap]") { + const size_t HEAP_SIZE = 4 * 1024; const uint32_t PATTERN = 0xABABDADA; - uint8_t small_heap[4 * 1024]; + uint8_t small_heap[HEAP_SIZE]; multi_heap_handle_t heap = multi_heap_register(small_heap, sizeof(small_heap)); uint32_t *a = (uint32_t *)multi_heap_malloc(heap, 64); @@ -404,7 +433,6 @@ TEST_CASE("multi_heap_realloc()", "[multi_heap]") REQUIRE( b > a); /* 'b' takes the block after 'a' */ *a = PATTERN; - uint32_t *c = (uint32_t *)multi_heap_realloc(heap, a, 72); REQUIRE( multi_heap_check(heap, true)); REQUIRE( c != NULL ); @@ -414,13 +442,12 @@ TEST_CASE("multi_heap_realloc()", "[multi_heap]") #ifndef MULTI_HEAP_POISONING_SLOW // "Slow" poisoning implementation doesn't reallocate in place, so these // test will fail... - uint32_t *d = (uint32_t *)multi_heap_realloc(heap, c, 36); REQUIRE( multi_heap_check(heap, true) ); REQUIRE( c == d ); /* 'c' block should be shrunk in-place */ REQUIRE( *d == PATTERN); - - uint32_t *e = (uint32_t *)multi_heap_malloc(heap, 64); + // biggest allocation possible to completely fill the block left free after it was reallocated + uint32_t *e = (uint32_t *)multi_heap_malloc(heap, 60); REQUIRE( multi_heap_check(heap, true)); REQUIRE( a == e ); /* 'e' takes the block formerly occupied by 'a' */ @@ -429,11 +456,7 @@ TEST_CASE("multi_heap_realloc()", "[multi_heap]") REQUIRE( multi_heap_check(heap, true) ); REQUIRE( f == b ); /* 'b' should be extended in-place, over space formerly occupied by 'd' */ -#ifdef MULTI_HEAP_POISONING -#define TOO_MUCH 7420 + 1 -#else -#define TOO_MUCH 7420 + 1 -#endif +#define TOO_MUCH HEAP_SIZE + 1 /* not enough contiguous space left in the heap */ uint32_t *g = (uint32_t *)multi_heap_realloc(heap, e, TOO_MUCH); REQUIRE( g == NULL ); @@ -443,7 +466,8 @@ TEST_CASE("multi_heap_realloc()", "[multi_heap]") g = (uint32_t *)multi_heap_realloc(heap, e, 128); REQUIRE( multi_heap_check(heap, true) ); REQUIRE( e == g ); /* 'g' extends 'e' in place, into the space formerly held by 'f' */ -#endif + +#endif // MULTI_HEAP_POISONING_SLOW } // TLSF only accepts heaps aligned to 4-byte boundary so @@ -542,8 +566,12 @@ TEST_CASE("multi_heap poisoning detection", "[multi_heap]") /* register the heap memory. One free block only will be available */ multi_heap_handle_t heap = multi_heap_register(heap_mem, HEAP_SIZE); + control_t *tlsf_ptr = (control_t*)(heap_mem + 20); + const size_t control_t_size = tlsf_ptr->size; + const size_t heap_t_size = 20; + /* offset in memory at which to find the first free memory byte */ - const size_t free_memory_offset = sizeof(multi_heap_info_t) + sizeof(control_t) + block_header_overhead; + const size_t free_memory_offset = heap_t_size + control_t_size + sizeof(block_header_t) - block_header_overhead; /* block header of the free block under test in the heap () */ const block_header_t* block = (block_header_t*)(heap_mem + free_memory_offset - sizeof(block_header_t));