25#include <freeradius-devel/util/talloc.h>
26#include <freeradius-devel/util/math.h>
44 TEST_CASE(
"talloc allocates child of context");
51 TEST_CASE(
"talloc_size allocates arbitrary size");
52 s = talloc_size(ctx, 100);
72 TEST_CASE(
"talloc_zero initializes to zero");
73 p = talloc_zero(ctx,
int);
77 TEST_CASE(
"talloc_zero_size initializes to zero");
78 buf = talloc_zero_size(ctx, 64);
80 for (i = 0; i < 64; i++) {
98 TEST_CASE(
"talloc_array allocates typed array");
99 arr = talloc_array(ctx,
int, 10);
101 TEST_CHECK(talloc_get_size(arr) == 10 *
sizeof(
int));
102 for (i = 0; i < 10; i++) arr[i] = (
int)i;
103 for (i = 0; i < 10; i++)
TEST_CHECK(arr[i] == (
int)i);
105 TEST_CASE(
"talloc_zero_array initializes to zero");
106 arr = talloc_zero_array(ctx,
int, 5);
108 for (i = 0; i < 5; i++)
TEST_CHECK(arr[i] == 0);
110 TEST_CASE(
"talloc_realloc grows array preserving content");
111 arr = talloc_array(ctx,
int, 4);
112 for (i = 0; i < 4; i++) arr[i] = (
int)(i + 100);
113 arr = talloc_realloc(ctx, arr,
int, 8);
115 for (i = 0; i < 4; i++)
TEST_CHECK(arr[i] == (
int)(i + 100));
116 TEST_CHECK(talloc_get_size(arr) == 8 *
sizeof(
int));
118 TEST_CASE(
"talloc_realloc shrinks array");
119 arr = talloc_realloc(ctx, arr,
int, 2);
123 TEST_CHECK(talloc_get_size(arr) == 2 *
sizeof(
int));
134 int *child1, *child2;
136 TEST_CASE(
"talloc_free(NULL) returns -1");
139 TEST_CASE(
"talloc_free recursively frees children");
141 child1 = talloc(ctx,
int);
143 child2 = talloc(child1,
int);
159 TEST_CASE(
"talloc_set_name_const / talloc_get_name roundtrip");
160 p = talloc_size(ctx, 10);
161 talloc_set_name_const(p,
"my_chunk");
162 TEST_CHECK(strcmp(talloc_get_name(p),
"my_chunk") == 0);
164 TEST_CASE(
"talloc_check_name succeeds on match");
165 TEST_CHECK(talloc_check_name(p,
"my_chunk") == p);
167 TEST_CASE(
"talloc_check_name returns NULL on mismatch");
168 TEST_CHECK(talloc_check_name(p,
"wrong_name") == NULL);
170 TEST_CASE(
"talloc_named_const sets name at creation");
171 p = talloc_named_const(ctx, 20,
"named_chunk");
173 TEST_CHECK(strcmp(talloc_get_name(p),
"named_chunk") == 0);
188 TEST_CASE(
"talloc_parent returns correct parent");
189 child = talloc(ctx,
int);
192 TEST_CASE(
"talloc_parent_name returns parent's name");
193 TEST_CHECK(strcmp(talloc_parent_name(child),
"test_parent") == 0);
195 TEST_CASE(
"talloc_parent of top-level returns NULL context");
201 void *
parent = talloc_parent(ctx);
213 TALLOC_CTX *ctx1, *ctx2;
220 TEST_CASE(
"talloc_steal moves child to new parent");
221 p = talloc(ctx1,
int);
224 ret = talloc_steal(ctx2, p);
229 TEST_CASE(
"talloc_steal NULL returns NULL");
232 TEST_CASE(
"talloc_steal to NULL reparents to null context");
233 p = talloc(ctx1,
int);
234 ret = talloc_steal(NULL, p);
247 TALLOC_CTX *ctx1, *ctx2;
253 TEST_CASE(
"talloc_move transfers ownership and NULLs source");
254 p = talloc(ctx1,
int);
256 moved = talloc_move(ctx2, &p);
271 TALLOC_CTX *ctx1, *ctx2;
278 TEST_CASE(
"talloc_reference creates a reference");
280 ref = talloc_reference(ctx2, str);
284 TEST_CASE(
"talloc_unlink removes the reference");
288 TEST_CASE(
"Multiple references increment count");
289 talloc_reference(ctx2, str);
290 talloc_reference(ctx2, str);
319 p = talloc(ctx,
int);
325 TEST_CASE(
"Destructor returning -1 prevents free");
332 p = talloc(ctx,
int);
350 TEST_CASE(
"talloc_strdup duplicates string");
356 TEST_CASE(
"talloc_strndup limits length");
361 TEST_CASE(
"talloc_strdup of NULL returns NULL");
378 TEST_CASE(
"talloc_asprintf formats string");
383 TEST_CASE(
"talloc_asprintf_append appends at string end");
385 s = talloc_asprintf_append(s,
" %s",
"world");
389 TEST_CASE(
"talloc_asprintf_append_buffer appends at buffer end");
391 s = talloc_asprintf_append_buffer(s,
"def");
406 TEST_CASE(
"talloc_pool creates a pool context");
407 pool = talloc_pool(NULL, 1024);
410 TEST_CASE(
"Allocations from pool succeed");
411 a = talloc(pool,
int);
412 b = talloc(pool,
int);
413 c = talloc(pool,
int);
417 *a = 1; *b = 2; *c = 3;
422 TEST_CASE(
"Pool children have pool as parent");
439 TEST_CASE(
"talloc_free_children frees all children");
441 p = talloc(ctx,
int);
443 p = talloc(ctx,
int);
445 p = talloc(ctx,
int);
450 talloc_free_children(ctx);
453 TEST_CASE(
"Context is still usable after free_children");
454 p = talloc(ctx,
int);
468 size_t total_size, total_blocks;
472 TEST_CASE(
"Empty context has size 0 and 1 block");
476 TEST_CASE(
"Allocations increase totals");
477 talloc_size(ctx, 100);
478 talloc_size(ctx, 200);
479 total_size = talloc_total_size(ctx);
480 total_blocks = talloc_total_blocks(ctx);
484 TEST_CASE(
"Nested children counted in totals");
486 void *child = talloc_size(ctx, 50);
487 talloc_size(child, 25);
505 TEST_CASE(
"talloc_get_size returns requested size");
506 p = talloc_size(ctx, 42);
509 TEST_CASE(
"talloc_get_size of NULL returns 0");
512 TEST_CASE(
"talloc_get_size after realloc returns new size");
513 p = talloc_realloc_size(ctx, p, 100);
524 TALLOC_CTX *root, *mid;
528 root = talloc_named_const(NULL, 0,
"root_ctx");
529 mid = talloc_named_const(root, 0,
"mid_ctx");
530 leaf = talloc(mid,
int);
532 TEST_CASE(
"Find existing parent by name");
533 found = talloc_find_parent_byname(leaf,
"root_ctx");
536 found = talloc_find_parent_byname(leaf,
"mid_ctx");
539 TEST_CASE(
"Return NULL for non-existent parent name");
540 found = talloc_find_parent_byname(leaf,
"nonexistent");
551 TALLOC_CTX *root, *mid;
555 mid = talloc(root,
char);
556 leaf = talloc(mid,
int);
562 TEST_CHECK(talloc_is_parent(leaf, root) == 1);
567 TEST_CHECK(talloc_is_parent(leaf, other) == 0);
579 TALLOC_CTX *old_parent, *new_parent;
586 TEST_CASE(
"talloc_reparent moves from old to new parent");
587 p = talloc(old_parent,
int);
589 ret = talloc_reparent(old_parent, new_parent, p);
594 TEST_CASE(
"talloc_reparent NULL returns NULL");
595 ret = talloc_reparent(old_parent, new_parent, NULL);
608 uint8_t src[] = {0x01, 0x02, 0x03, 0x04};
613 TEST_CASE(
"talloc_memdup duplicates bytes");
614 dup = talloc_memdup(ctx, src,
sizeof(src));
616 TEST_CHECK(memcmp(dup, src,
sizeof(src)) == 0);
617 TEST_CHECK(talloc_get_size(dup) ==
sizeof(src));
635 TEST_CASE(
"Deep hierarchy (100 levels) works");
636 for (i = 0; i < 100; i++) {
637 current = talloc_size(current, 16);
641 TEST_CASE(
"Total blocks counts all levels");
644 TEST_CASE(
"Free cleans up entire hierarchy");
658 TEST_CASE(
"talloc_strndup_append appends limited length");
660 s = talloc_strndup_append(s,
" world!!", 6);
664 TEST_CASE(
"talloc_strndup_append_buffer appends at buffer end");
666 s = talloc_strndup_append_buffer(s,
"defgh", 3);
684 TEST_CASE(
"increase_ref_count succeeds");
686 ret = talloc_increase_ref_count(str);
691 ret = talloc_increase_ref_count(str);
705 ret = talloc_total_blocks(ctx);
739 TEST_CASE(
"Duplicate NULL returns NULL");
783 TEST_CHECK(strcmp(str,
"hello world 42") == 0);
803 TEST_CASE(
"Duplicate string with embedded NUL");
810 TEST_CASE(
"Duplicate zero-length string");
833 TEST_CHECK(strcmp(result,
"hello world") == 0);
835 TEST_CASE(
"Append to NULL creates new string");
853 TEST_CASE(
"Realloc NULL allocates new buffer");
857 TEST_CHECK(talloc_array_length(result) == 11);
859 TEST_CASE(
"Realloc existing buffer to smaller size");
919 void **array, **result;
924 array = talloc_array(ctx,
void *, 3);
925 array[0] = (
void *)1;
926 array[1] = (
void *)2;
927 array[2] = (
void *)3;
934 TEST_CASE(
"NULL terminate NULL returns NULL");
955 TALLOC_CTX *ctx, *fire;
960 TEST_CASE(
"Destructor fires when fire_ctx is freed");
962 fire = talloc(ctx,
int);
969 TEST_CASE(
"Manual disarm via talloc_destructor_disarm");
971 fire = talloc(ctx,
int);
990 TALLOC_CTX *
parent, *child;
993 TEST_CASE(
"Child freed when parent freed");
1008 TEST_CASE(
"Header size is positive and reasonable");
1014 TEST_CASE(
"Repeated calls return same value");
1030 arr = talloc_array(ctx,
uint8_t, 4);
1032 memset(arr, 0xff, 4);
1034 TEST_CASE(
"Realloc larger zeros new portion");
1039 for (i = 0; i < 4; i++) {
1044 for (i = 4; i < 16; i++) {
1056 TALLOC_CTX *ctx, *ref_ctx;
1063 TEST_CASE(
"Decrease ref count with no references frees memory");
1072 TEST_CASE(
"With a reference, unlinks instead of freeing");
1074 talloc_reference(ref_ctx, str);
1087 TALLOC_CTX *ctx, *array;
1089 size_t page_size = (
size_t)getpagesize();
1093 TEST_CASE(
"Aligned array returns non-NULL");
1098 TEST_CASE(
"Start address is page-aligned");
1099 TEST_CHECK(((uintptr_t)start % page_size) == 0);
1118 if ((hdr <= 0) || (hdr > 4096) || (size > (SIZE_MAX / 2))) {
1119 TEST_ASSERT_(
false,
"talloc_hdr_size() returned %zd for size %zu", hdr, size);
1129 void *a, *b, *c, *big;
1133 TEST_CASE(
"An empty pool uses nothing");
1134 pool = talloc_pool(NULL, 4096);
1141 TEST_CASE(
"With no frees, used and live are the sum of the chunk footprints");
1142 a = talloc_size(pool, 10);
1143 b = talloc_size(pool, 100);
1144 c = talloc_size(pool, 20);
1153 TEST_CASE(
"Freeing a chunk below the highest leaves a hole: used stays, live drops");
1162 TEST_CASE(
"A chunk too large for the pool overflows, and is not live in the pool");
1163 big = talloc_size(pool, 8192);
#define TEST_ASSERT_(cond,...)
#define TEST_ASSERT(cond)
Common initialisation for acutest binaries.
#define ROUND_UP_POW2(_num, _mul)
Round up - Only works if _mul is a power of 2 but avoids division.
void ** talloc_array_null_terminate(void **array)
Add a NULL pointer to an array of pointers.
fr_talloc_destructor_t * talloc_destructor_add(TALLOC_CTX *fire_ctx, TALLOC_CTX *disarm_ctx, fr_talloc_free_func_t func, void const *uctx)
Add an additional destructor to a talloc chunk.
ssize_t talloc_hdr_size(void)
Calculate the size of the talloc chunk header.
char * talloc_bstr_realloc(TALLOC_CTX *ctx, char *in, size_t inlen)
Trim a bstr (char) buffer.
size_t talloc_pool_used(bool *overflowed, size_t *live, TALLOC_CTX const *pool, size_t pool_size)
Measure how many bytes of a talloc pool are used and live, and whether the pool overflowed.
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
TALLOC_CTX * talloc_aligned_array(TALLOC_CTX *ctx, void **start, size_t alignment, size_t size)
Return a page aligned talloc memory array.
int talloc_link_ctx(TALLOC_CTX *parent, TALLOC_CTX *child)
Link two different parent and child contexts, so the child is freed before the parent.
uint8_t * talloc_typed_memdup(TALLOC_CTX *ctx, uint8_t const *in, size_t inlen)
Call talloc_memdup, setting the type on the new chunk correctly.
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
int talloc_decrease_ref_count(void const *ptr)
Decrease the reference count on a ptr.
char * talloc_typed_strndup(TALLOC_CTX *ctx, char const *p, size_t len)
Call talloc_strndup, setting the type on the new chunk correctly.
char * talloc_bstr_append(TALLOC_CTX *ctx, char *to, char const *from, size_t from_len)
Append a bstr to a bstr.
void talloc_destructor_disarm(fr_talloc_destructor_t *d)
Disarm a destructor and free all memory allocated in the trigger ctxs.
int talloc_memcmp_bstr(char const *a, char const *b)
Compares two talloced char arrays with memcmp.
#define talloc_strndup(_ctx, _str, _len)
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
#define talloc_strdup(_ctx, _str)
#define talloc_realloc_zero(_ctx, _ptr, _type, _count)
Structure to record a destructor operation on a specific talloc chunk.
static int native_destructor_count
static void test_talloc_bstrndup(void)
static void test_talloc_steal(void)
static void test_talloc_free_children(void)
static void test_talloc_get_size(void)
static int test_fr_destructor_func(UNUSED void *fire_ctx, void *uctx)
static int native_destructor(int *ptr)
static void test_talloc_decrease_ref_count(void)
static void test_talloc_hdr_size(void)
static void test_talloc_zero(void)
static void test_talloc_typed_memdup(void)
static void test_talloc_is_parent(void)
static void test_talloc_pool_used(void)
static void test_talloc_move(void)
static void test_talloc_parent(void)
static void test_talloc_typed_strndup(void)
static void const * fr_destructor_uctx
static void test_talloc_destructor_add(void)
static void test_talloc_bstr_append(void)
static void test_talloc_reparent(void)
static void test_talloc_deep_hierarchy(void)
static void test_talloc_asprintf(void)
static void test_talloc_reference(void)
static void test_talloc_typed_asprintf(void)
static void test_talloc_naming(void)
static void test_talloc_find_parent_byname(void)
static void test_talloc_typed_strdup(void)
static void test_talloc_basic(void)
static void test_talloc_link_ctx(void)
static void test_talloc_aligned_array(void)
static void test_talloc_free(void)
static void test_talloc_array(void)
static void test_talloc_strdup(void)
static void test_talloc_set_destructor(void)
static void test_talloc_array_null_terminate(void)
static void test_talloc_increase_ref_count(void)
static void test_talloc_strndup_append(void)
static void test_talloc_bstr_realloc(void)
static int fr_destructor_called
static void test_talloc_realloc_zero(void)
static void test_talloc_memcmp_bstr(void)
static void test_talloc_pool(void)
static void test_talloc_memdup(void)
static size_t pool_chunk_footprint(size_t size)
static void test_talloc_total_size(void)