|
|
@@ -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 <string.h>
|
|
|
#include <assert.h>
|
|
|
|
|
|
+/* 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));
|