The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
talloc.c
Go to the documentation of this file.
1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** Functions which we wish were included in the standard talloc distribution
18 *
19 * @file src/lib/util/talloc.c
20 *
21 * @copyright 2017 The FreeRADIUS server project
22 * @copyright 2017 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23 */
24RCSID("$Id: cecafa57af391478aa6aaabed4e9b5ed94b7aab9 $")
25
26#include <freeradius-devel/util/atexit.h>
27#include <freeradius-devel/util/debug.h>
28#include <freeradius-devel/util/dlist.h>
29#include <freeradius-devel/util/syserror.h>
30
31
32static TALLOC_CTX *global_ctx;
33static _Thread_local TALLOC_CTX *thread_local_ctx;
34
35/** A wrapper that can be passed to tree or hash alloc functions that take a #fr_free_t
36 */
38{
40}
41
42/** Retrieve the current talloc NULL ctx
43 *
44 * Talloc doesn't provide a function to retrieve the top level memory tracking context.
45 * This function does that...
46 *
47 * @return the current talloc NULL context or NULL if memory tracking is not enabled.
48 */
49void *talloc_null_ctx(void)
50{
51 TALLOC_CTX *null_ctx;
52 bool *tmp;
53
54 tmp = talloc(NULL, bool);
55 null_ctx = talloc_parent(tmp);
56 talloc_free(tmp);
57
58 return null_ctx;
59}
60
61/** Called with the fire_ctx is freed
62 *
63 */
65{
66 if (d->ds) {
67 talloc_set_destructor(d->ds, NULL); /* Disarm the disarmer */
68 TALLOC_FREE(d->ds); /* Free the disarm trigger ctx */
69 }
70
71 return d->func(d->fire, d->uctx);
72}
73
74/** Called when the disarm_ctx ctx is freed
75 *
76 */
78{
79 talloc_set_destructor(ds->d, NULL); /* Disarm the destructor */
80 return talloc_free(ds->d); /* Free memory allocated to the destructor */
81}
82
83/** Add an additional destructor to a talloc chunk
84 *
85 * @param[in] fire_ctx When this ctx is freed the destructor function
86 * will be called.
87 * @param[in] disarm_ctx When this ctx is freed the destructor will be
88 * disarmed. May be NULL. #talloc_destructor_disarm
89 * may be used to disarm the destructor too.
90 * @param[in] func to call when the fire_ctx is freed.
91 * @param[in] uctx data to pass to the above function.
92 * @return
93 * - A handle to access the destructor on success.
94 * - NULL on failure.
95 */
96fr_talloc_destructor_t *talloc_destructor_add(TALLOC_CTX *fire_ctx, TALLOC_CTX *disarm_ctx,
97 fr_talloc_free_func_t func, void const *uctx)
98{
100
101 if (!fire_ctx) {
102 fr_strerror_const("No firing ctx provided when setting destructor");
103 return NULL;
104 }
105
106 d = talloc_zero(fire_ctx, fr_talloc_destructor_t);
107 if (!d) {
108 oom:
109 fr_strerror_const("Out of Memory");
110 return NULL;
111 }
112
113 d->fire = fire_ctx;
114 d->func = func;
115 memcpy(&d->uctx, &uctx, sizeof(d->uctx));
116
117 if (disarm_ctx) {
119
120 ds = talloc(disarm_ctx, fr_talloc_destructor_disarm_t);
121 if (!ds) {
122 talloc_free(d);
123 goto oom;
124 }
125 ds->d = d;
126 d->ds = ds;
127 talloc_set_destructor(ds, _talloc_destructor_disarm);
128 }
129
130 talloc_set_destructor(d, _talloc_destructor_fire);
131
132 return d;
133}
134
135/** Disarm a destructor and free all memory allocated in the trigger ctxs
136 *
137 */
139{
140 if (d->ds) {
141 talloc_set_destructor(d->ds, NULL); /* Disarm the disarmer */
142 TALLOC_FREE(d->ds); /* Free the disarmer ctx */
143 }
144
145 talloc_set_destructor(d, NULL); /* Disarm the destructor */
146 talloc_free(d); /* Free the destructor ctx */
147}
148
149static int _talloc_link_ctx_free(UNUSED void *parent, void *child)
150{
151 talloc_free(child);
152
153 return 0;
154}
155
156/** Link two different parent and child contexts, so the child is freed before the parent
157 *
158 * @note This is not thread safe. Do not free parent before threads are joined, do not call from a
159 * child thread.
160 *
161 * @param parent who's fate the child should share.
162 * @param child bound to parent's lifecycle.
163 * @return
164 * - 0 on success.
165 * - -1 on failure.
166 */
167int talloc_link_ctx(TALLOC_CTX *parent, TALLOC_CTX *child)
168{
169 if (!talloc_destructor_add(parent, child, _talloc_link_ctx_free, child)) return -1;
170
171 return 0;
172}
173
174/** Return a page aligned talloc memory array
175 *
176 * Because we can't intercept talloc's malloc() calls, we need to do some tricks
177 * in order to get the first allocation in the array page aligned, and to limit
178 * the size of the array to a multiple of the page size.
179 *
180 * The reason for wanting a page aligned talloc array, is it allows us to
181 * mprotect() the pages that belong to the array.
182 *
183 * Talloc chunks appear to be allocated within the protected region, so this should
184 * catch frees too.
185 *
186 * @param[in] ctx to allocate array memory in.
187 * @param[out] start The first aligned address in the array.
188 * @param[in] alignment What alignment the memory chunk should have.
189 * @param[in] size How big to make the array. Will be corrected to a multiple
190 * of the page size. The actual array size will be size
191 * rounded to a multiple of the (page_size), + page_size
192 * @return
193 * - A talloc chunk on success.
194 * - NULL on failure.
195 */
196TALLOC_CTX *talloc_aligned_array(TALLOC_CTX *ctx, void **start, size_t alignment, size_t size)
197{
198 size_t rounded;
199 size_t array_size;
200 void *next;
201 TALLOC_CTX *array;
202
203 rounded = ROUND_UP(size, alignment); /* Round up to a multiple of the page size */
204 if (rounded == 0) rounded = alignment;
205
206 array_size = rounded + alignment;
207 array = talloc_array(ctx, uint8_t, array_size); /* Over allocate */
208 if (!array) {
209 fr_strerror_const("Out of memory");
210 return NULL;
211 }
212
213 next = (void *)ROUND_UP((uintptr_t)array, alignment); /* Round up address to the next multiple */
214 *start = next;
215
216 return array;
217}
218
219/** How big the chunk header is
220 *
221 * Non-zero portion will always fit in a uint8_t, so we don't need to worry about atomicity.
222 */
223static size_t t_hdr_size;
224
225/** Calculate the size of talloc chunk headers, once, on startup
226 *
227 */
228static void _talloc_hdr_size(void)
229{
230 TALLOC_CTX *pool;
231 void *chunk;
232
233 pool = talloc_pool(NULL, 1024); /* Allocate 1k of memory, this will always be bigger than the chunk header */
234 if (unlikely(pool == NULL)) {
235 oom:
236 fr_strerror_const("Out of memory");
237 return;
238 }
239 chunk = talloc_size(pool, 1); /* Get the starting address */
240 if (unlikely(chunk == NULL)) goto oom;
241
242 /*
243 * Sanity check... make sure the chunk is within the pool
244 * if it's not, we're in trouble.
245 */
246 if (!fr_cond_assert((chunk > pool) && ((uintptr_t)chunk < ((uintptr_t)pool + 1024)))) {
247 fr_strerror_const("Initial allocation outside of pool memory");
248 return;
249 }
250
251 /*
252 * Talloc returns the address after the chunk header, so
253 * the address of the pool is <malloc address> + <hdr_size>.
254 *
255 * If we allocate a chunk inside the pool, then the address
256 * of the chunk will be <malloc address> + <hdr_size> + <hdr_size>.
257 * If we subtrace the chunk from the pool address, we get
258 * the size of the talloc header.
259 */
260 t_hdr_size = (uintptr_t)chunk - (uintptr_t)pool;
261
262 talloc_free(pool); /* Free the memory we used */
263}
264
265/** Calculate the size of the talloc chunk header
266 *
267 * @return
268 * - >0 the size of the talloc chunk header.
269 * - -1 on error.
270 */
272{
273 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
274
275 if (t_hdr_size > 0) return t_hdr_size; /* We've already calculated it */
276
277 if (pthread_once(&once_control, _talloc_hdr_size) != 0) {
278 fr_strerror_printf("pthread_once failed: %s", fr_syserror(errno));
279 return -1;
280 }
281 if (t_hdr_size == 0) return -1; /* Callback should set error */
282
283 return t_hdr_size;
284}
285
286/** Return a page aligned talloc memory pool
287 *
288 * Because we can't intercept talloc's malloc() calls, we need to do some tricks
289 * in order to get the first allocation in the pool page aligned, and to limit
290 * the size of the pool to a multiple of the page size.
291 *
292 * The reason for wanting a page aligned talloc pool, is it allows us to
293 * mprotect() the pages that belong to the pool.
294 *
295 * Talloc chunks appear to be allocated within the protected region, so this should
296 * catch frees too.
297 *
298 * @param[in] ctx to allocate pool memory in.
299 * @param[out] start A page aligned address within the pool. This can be passed
300 * to mprotect().
301 * @param[out] end_len how many bytes to protect.
302 * @param[in] headers how much room we should allocate for talloc headers.
303 * This value should usually be >= 1.
304 * @param[in] size How big to make the pool. Will be corrected to a multiple
305 * of the page size. The actual pool size will be size
306 * rounded to a multiple of the (page_size), + page_size
307 */
308TALLOC_CTX *talloc_page_aligned_pool(TALLOC_CTX *ctx, void **start, size_t *end_len, unsigned int headers, size_t size)
309{
310 size_t rounded, alloced, page_size = (size_t)getpagesize();
311 ssize_t hdr_size;
312 void *next;
313 TALLOC_CTX *pool;
314
315 hdr_size = talloc_hdr_size();
316 if (hdr_size < 0) return NULL;
317
318 size += (hdr_size * headers); /* Add more space for the chunks headers of the pool's children */
319 size += hdr_size; /* Add one more header to the pool for the padding allocation */
320
321 /*
322 * Allocate enough space for the padding header the other headers
323 * and the actual data, and sure it's a multiple of the page_size.
324 *
325 * |<--- page_size --->|<-- page_size -->|
326 * |<-- hdr_size -->|<-- size -->|
327 */
328 if (size % page_size == 0) {
329 rounded = size;
330 } else {
331 rounded = ROUND_UP(size, page_size);
332 }
333
334 /*
335 * Add another page, so that we can align the first allocation in
336 * the pool to a page boundary. We have no idea what chunk malloc
337 * will give to talloc, and what the first address after adding the
338 * pools header will be
339 */
340 alloced = rounded + page_size;
341 pool = talloc_pool(ctx, alloced);
342 if (!pool) {
343 fr_strerror_const("Out of memory");
344 return NULL;
345 }
346
347 /*
348 * If we didn't get lucky, and the first address in the pool is
349 * not the start of a page, we need to allocate some padding to
350 * get the first allocation in the pool to be on or after the
351 * start of the next page.
352 */
353 if ((uintptr_t)pool % page_size != 0) {
354 size_t pad_size;
355 void *padding;
356
357 next = (void *)ROUND_UP((uintptr_t)pool, page_size); /* Round up address to the next page */
358
359 /*
360 * We don't care if the first address if on a page
361 * boundary, just that it comes after one.
362 */
363 pad_size = ((uintptr_t)next - (uintptr_t)pool);
364 if (pad_size > (size_t) hdr_size) {
365 pad_size -= hdr_size; /* Save ~111 bytes by not over-padding */
366 } else {
367 pad_size = 0; /* Allocate as few bytes as possible */
368 }
369
370 padding = talloc_size(pool, pad_size);
371 if (!fr_cond_assert(((uintptr_t)padding + (uintptr_t)pad_size) >= (uintptr_t)next)) {
372 fr_strerror_const("Failed padding pool memory");
373 return NULL;
374 }
375 } else {
376 next = pool;
377 }
378
379 *start = next; /* This is the address we feed into mprotect */
380 *end_len = rounded; /* This is how much memory we protect */
381
382 /*
383 * Start address must be page aligned
384 */
385 fr_assert(((uintptr_t)*start % page_size) == 0);
386
387 /*
388 * For our sanity, length must be a multiple of the page size.
389 * mprotect will silently protect an entire additional page
390 * if length is not a multiple of page size.
391 */
392 fr_assert(((uintptr_t)*end_len % page_size) == 0);
393
394 /*
395 * We can't protect pages before the pool
396 */
397 fr_assert(*start >= pool);
398
399 /*
400 * We can't protect pages after the pool
401 */
402 fr_assert(((uintptr_t)*start + *end_len) <= ((uintptr_t)pool + alloced));
403
404 return pool;
405}
406
407/** Version of talloc_realloc which zeroes out freshly allocated memory
408 *
409 * @param[in] ctx talloc ctx to allocate in.
410 * @param[in] ptr the pointer to the old memory.
411 * @param[in] elem_size the size of each element in the array.
412 * @param[in] count the number of elements in the array.
413 * @param[in] name the name of the new chunk.
414 * @return
415 * - A pointer to the new memory.
416 * - NULL on error.
417 */
418void *_talloc_realloc_zero(const void *ctx, void *ptr, size_t elem_size, unsigned count, const char *name)
419{
420 size_t old_size = talloc_get_size(ptr);
421 size_t new_size;
422
423 void *new = _talloc_realloc_array(ctx, ptr, elem_size, count, name);
424 if (!new) return NULL;
425
426 new_size = talloc_array_length((uint8_t *) new);
427 if (new_size > old_size) {
428 memset((uint8_t *)new + old_size, 0, new_size - old_size);
429 }
430
431 return new;
432}
433
434/** Call talloc_memdup, setting the type on the new chunk correctly
435 *
436 * @param[in] ctx The talloc context to hang the result off.
437 * @param[in] in The data you want to duplicate.
438 * @param[in] inlen the length of the data to be duplicated.
439 * @return
440 * - Duplicated data.
441 * - NULL on error.
442 *
443 * @hidecallergraph
444 */
445uint8_t *talloc_typed_memdup(TALLOC_CTX *ctx, uint8_t const *in, size_t inlen)
446{
447 uint8_t *n;
448
449 n = talloc_memdup(ctx, in, inlen);
450 if (unlikely(!n)) return NULL;
451 talloc_set_type(n, uint8_t);
452
453 return n;
454}
455
456/** Call talloc_strdup, setting the type on the new chunk correctly
457 *
458 * For some bizarre reason the talloc string functions don't set the
459 * memory chunk type to char, which causes all kinds of issues with
460 * verifying fr_pair_ts.
461 *
462 * @param[in] ctx The talloc context to hang the result off.
463 * @param[in] p The string you want to duplicate.
464 * @return
465 * - Duplicated string.
466 * - NULL on error.
467 *
468 * @hidecallergraph
469 */
470char *talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
471{
472 char *n;
473
474#undef talloc_strdup
475 n = talloc_strdup(ctx, p);
476 if (unlikely(!n)) return NULL;
477 talloc_set_type(n, char);
478
479 return n;
480}
481
482/** Call talloc_strndup, setting the type on the new chunk correctly
483 *
484 * This function is similar to talloc_typed_strdup but gets the chunk
485 * length using talloc functions.
486 *
487 * @param[in] ctx The talloc context to hang the result off.
488 * @param[in] p The string you want to duplicate.
489 * @return
490 * - Duplicated string.
491 * - NULL on error.
492 *
493 * @hidecallergraph
494 */
495char *talloc_typed_strdup_buffer(TALLOC_CTX *ctx, char const *p)
496{
497 char *n;
498
499 n = talloc_strndup(ctx, p, talloc_strlen(p));
500 if (unlikely(!n)) return NULL;
501 talloc_set_type(n, char);
502
503 return n;
504}
505
506/** Call talloc_strndup, setting the type on the new chunk correctly
507 *
508 * For some bizarre reason the talloc string functions don't set the
509 * memory chunk type to char, which causes all kinds of issues with
510 * verifying fr_pair_ts.
511 *
512 * @param[in] ctx The talloc context to hang the result off.
513 * @param[in] p The string you want to duplicate.
514 * @param[in] len The length of the string
515 * @return
516 * - Duplicated string.
517 * - NULL on error.
518 *
519 * @hidecallergraph
520 */
521char *talloc_typed_strndup(TALLOC_CTX *ctx, char const *p, size_t len)
522{
523 char *n;
524
525#undef talloc_strndup
526 n = talloc_strndup(ctx, p, len);
527 if (unlikely(!n)) return NULL;
528 talloc_set_type(n, char);
529
530 return n;
531}
532
533/** Call talloc vasprintf, setting the type on the new chunk correctly
534 *
535 * For some bizarre reason the talloc string functions don't set the
536 * memory chunk type to char, which causes all kinds of issues with
537 * verifying fr_pair_ts.
538 *
539 * @param[in] ctx The talloc context to hang the result off.
540 * @param[in] fmt The format string.
541 * @return
542 * - Formatted string.
543 * - NULL on error.
544 */
545char *talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt, ...)
546{
547 char *n;
548 va_list ap;
549
550 va_start(ap, fmt);
551 n = talloc_vasprintf(ctx, fmt, ap);
552 va_end(ap);
553 if (unlikely(!n)) return NULL;
554 talloc_set_type(n, char);
555
556 return n;
557}
558
559/** Call talloc vasprintf, setting the type on the new chunk correctly
560 *
561 * For some bizarre reason the talloc string functions don't set the
562 * memory chunk type to char, which causes all kinds of issues with
563 * verifying fr_pair_ts.
564 *
565 * @param[in] ctx The talloc context to hang the result off.
566 * @param[in] fmt The format string.
567 * @param[in] ap varadic arguments.
568 * @return
569 * - Formatted string.
570 * - NULL on error.
571 */
572char *talloc_typed_vasprintf(TALLOC_CTX *ctx, char const *fmt, va_list ap)
573{
574 char *n;
575
576 n = talloc_vasprintf(ctx, fmt, ap);
577 if (unlikely(!n)) return NULL;
578 talloc_set_type(n, char);
579
580 return n;
581}
582
583/** Binary safe strdup function
584 *
585 * @param[in] ctx the talloc context to allocate new buffer in.
586 * @param[in] in String to dup, may contain embedded '\0'.
587 * @return duped string.
588 */
589char *talloc_bstrdup(TALLOC_CTX *ctx, char const *in)
590{
591 char *p;
592 size_t inlen = talloc_array_length(in);
593
594 if (inlen == 0) inlen = 1;
595
596 p = talloc_array(ctx, char, inlen);
597 if (unlikely(!p)) return NULL;
598
599 /*
600 * C99 (7.21.1/2) - Length zero results in noop
601 *
602 * But ubsan still flags this, grrr.
603 */
604 if (inlen > 0) memcpy(p, in, inlen - 1);
605 p[inlen - 1] = '\0';
606
607 return p;
608}
609
610/** Binary safe strndup function
611 *
612 * @param[in] ctx he talloc context to allocate new buffer in.
613 * @param[in] in String to dup, may contain embedded '\0'.
614 * @param[in] inlen Number of bytes to dup.
615 * @return duped string.
616 */
617char *talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
618{
619 char *p;
620
621 p = talloc_array(ctx, char, inlen + 1);
622 if (unlikely(!p)) return NULL;
623
624 /*
625 * C99 (7.21.1/2) - Length zero results in noop
626 *
627 * But ubsan still flags this, grrr.
628 */
629 if (inlen > 0) memcpy(p, in, inlen);
630 p[inlen] = '\0';
631
632 return p;
633}
634
635/** Append a bstr to a bstr
636 *
637 * @param[in] ctx to allocated.
638 * @param[in] to string to append to.
639 * @param[in] from string to append from.
640 * @param[in] from_len Length of from.
641 * @return
642 * - Realloced buffer containing both to and from.
643 * - NULL on failure. To will still be valid.
644 */
645char *talloc_bstr_append(TALLOC_CTX *ctx, char *to, char const *from, size_t from_len)
646{
647 char *n;
648 size_t to_len = 0;
649
650 if (to) {
651 to_len = talloc_array_length(to);
652 if (to[to_len - 1] == '\0') to_len--; /* Inlen should be length of input string */
653 }
654
655 n = talloc_realloc_size(ctx, to, to_len + from_len + 1);
656 if (!n) {
657 fr_strerror_printf("Extending bstr buffer to %zu bytes failed", to_len + from_len + 1);
658 return NULL;
659 }
660
661 memcpy(n + to_len, from, from_len);
662 n[to_len + from_len] = '\0';
663 talloc_set_type(n, char);
664
665 return n;
666}
667
668/** Trim a bstr (char) buffer
669 *
670 * Reallocs to inlen + 1 and '\0' terminates the string buffer.
671 *
672 * @param[in] ctx to realloc buffer into.
673 * @param[in] in string to trim. Will be invalid after
674 * this function returns. If NULL a new zero terminated
675 * buffer of inlen bytes will be allocated.
676 * @param[in] inlen Length to trim string to.
677 * @return
678 * - The realloced string on success. in then points to invalid memory.
679 * - NULL on failure. In will still be valid.
680 */
681char *talloc_bstr_realloc(TALLOC_CTX *ctx, char *in, size_t inlen)
682{
683 char *n;
684
685 if (!in) {
686 n = talloc_array(ctx, char, inlen + 1);
687 if (!n) return NULL;
688 n[0] = '\0';
689 return n;
690 }
691
692 n = talloc_realloc_size(ctx, in, inlen + 1);
693 if (unlikely(!n)) return NULL;
694
695 n[inlen] = '\0';
696 talloc_set_type(n, char);
697
698 return n;
699}
700
701/** Concatenate to + ...
702 *
703 * @param[in] ctx to allocate realloced buffer in.
704 * @param[in] to talloc string buffer to append to.
705 * @param[in] argc how many variadic arguments were passed.
706 * @param[in] ... talloc string buffer(s) to append.
707 * Arguments can be NULL to simplify
708 * calling logic.
709 * @return
710 * - NULL if to or from are NULL or if the realloc fails.
711 * Note: You'll still need to free to if this function
712 * returns NULL.
713 * - The concatenation of to + from. After this function
714 * returns to may point to invalid memory and should
715 * not be used.
716 */
717char *talloc_buffer_append_variadic_buffer(TALLOC_CTX *ctx, char *to, int argc, ...)
718{
719 va_list ap_val, ap_len;
720 int i;
721
722 size_t to_len, total_len = 0;
723 char *out, *p;
724
725 if (!to) return NULL;
726
727 va_start(ap_val, argc);
728 va_copy(ap_len, ap_val);
729
730 total_len += to_len = talloc_strlen(to);
731
732 /*
733 * Figure out how much we need to realloc
734 */
735 for (i = 0; i < argc; i++) {
736 char *arg;
737
738 arg = va_arg(ap_len, char *);
739 if (!arg) continue;
740
741 total_len += (talloc_strlen(arg));
742 }
743
744 /*
745 * It's a noop...
746 */
747 if (total_len == to_len) {
748 va_end(ap_val);
749 va_end(ap_len);
750 return to;
751 }
752
753 out = talloc_realloc(ctx, to, char, total_len + 1);
754 if (!out) goto finish;
755
756 p = out + to_len;
757
758 /*
759 * Copy the args in
760 */
761 for (i = 0; i < argc; i++) {
762 char *arg;
763 size_t len;
764
765 arg = va_arg(ap_val, char *);
766 if (!arg) continue;
767
768 len = talloc_strlen(arg);
769
770 memcpy(p, arg, len);
771 p += len;
772 }
773 *p = '\0';
774
775finish:
776 va_end(ap_val);
777 va_end(ap_len);
778
779 return out;
780}
781
782/** Compares two talloced char arrays with memcmp
783 *
784 * Talloc arrays carry their length as part of the structure, so can be passed to a generic
785 * comparison function.
786 *
787 * @param a Pointer to first array.
788 * @param b Pointer to second array.
789 * @return
790 * - 0 if the arrays match.
791 * - a positive or negative integer otherwise.
792 */
793int talloc_memcmp_bstr(char const *a, char const *b)
794{
795 size_t a_len, b_len;
796
797 a_len = talloc_array_length(a);
798 b_len = talloc_array_length(b);
799
800 if (a_len > b_len) return +1;
801 if (a_len < b_len) return -1;
802
803 return memcmp(a, b, a_len);
804}
805
806/** Decrease the reference count on a ptr
807 *
808 * Ptr will be freed if count reaches zero.
809 *
810 * This is equivalent to talloc 1.0 behaviour of talloc_free.
811 *
812 * @param ptr to decrement ref count for.
813 * @return
814 * - 0 The memory was freed.
815 * - >0 How many references remain.
816 */
817int talloc_decrease_ref_count(void const *ptr)
818{
819 size_t ref_count;
820 void *to_free;
821
822 if (!ptr) return 0;
823
824 memcpy(&to_free, &ptr, sizeof(to_free));
825
826 ref_count = talloc_reference_count(to_free);
827 if (ref_count == 0) {
828 talloc_free(to_free);
829 } else {
830 talloc_unlink(talloc_parent(ptr), to_free);
831 if (talloc_reference_count(to_free) == 0) talloc_free(to_free);
832 }
833
834 return ref_count;
835}
836
837/** Add a NULL pointer to an array of pointers
838 *
839 * This is needed by some 3rd party libraries which take NULL terminated
840 * arrays for arguments.
841 *
842 * If allocation fails, NULL will be returned and the original array
843 * will not be touched.
844 *
845 * @param[in] array to null terminate. Will be invalidated (realloced).
846 * @return
847 * - NULL if array is NULL, or if reallocation fails.
848 * - A realloced version of array with an additional NULL element.
849 */
850void **talloc_array_null_terminate(void **array)
851{
852 size_t len;
853 TALLOC_CTX *ctx;
854 void **new;
855 size_t size;
856
857 if (!array) return NULL;
858
859 len = talloc_array_length(array);
860 ctx = talloc_parent(array);
861 size = talloc_get_size(array) / talloc_array_length(array);
862
863 new = _talloc_realloc_array(ctx, array, size, len + 1, talloc_get_name(array));
864 if (!new) return NULL;
865
866 new[len] = NULL;
867
868 return new;
869}
870
871/** Callback to free the autofree ctx on global exit
872 *
873 */
874static int _autofree_on_exit(void *af)
875{
876 talloc_set_destructor(af, NULL);
877 return talloc_free(af);
878}
879
880/** Ensures in the autofree ctx is manually freed, things don't explode atexit
881 *
882 */
883static int _autofree_global_destructor(TALLOC_CTX *af)
884{
886}
887
889{
890 TALLOC_CTX *af = global_ctx;
891
892 if (!af) {
893 af = talloc_init_const("global_autofree_context");
894 if (unlikely(!af)) return NULL;
895
896 talloc_set_destructor(af, _autofree_global_destructor);
897
899 global_ctx = af;
900 }
901
902 return af;
903}
904
905/** Ensures in the autofree ctx is manually freed, things don't explode atexit
906 *
907 */
908static int _autofree_thread_local_destructor(TALLOC_CTX *af)
909{
911}
912
913/** Get a thread-safe autofreed ctx that will be freed when the thread or process exits
914 *
915 * @note This should be used in place of talloc_autofree_context (which is now deprecated)
916 * @note Will not be thread-safe if NULL tracking is enabled.
917 *
918 * @return A talloc ctx which will be freed when the thread or process exits.
919 */
921{
922 TALLOC_CTX *af = thread_local_ctx;
923
924 if (!af) {
925 af = talloc_init_const("thread_local_autofree_context");
926 if (unlikely(!af)) return NULL;
927
928 talloc_set_destructor(af, _autofree_thread_local_destructor);
929
931 }
932
933 return af;
934}
va_end(args)
int n
Definition acutest.h:577
static int const char * fmt
Definition acutest.h:573
va_start(args, fmt)
unsigned int fr_atexit_global_disarm(bool uctx_scope, fr_atexit_t func, void const *uctx)
Remove a specific global destructor (without executing it)
Definition atexit.c:228
#define fr_atexit_thread_local_disarm(...)
Definition atexit.h:230
#define fr_atexit_global(_func, _uctx)
Add a free function to the global free list.
Definition atexit.h:58
#define fr_atexit_thread_local(_name, _free, _uctx)
Definition atexit.h:220
#define RCSID(id)
Definition build.h:512
#define unlikely(_x)
Definition build.h:407
#define UNUSED
Definition build.h:336
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:141
static fr_slen_t in
Definition dict.h:882
talloc_free(hp)
#define ROUND_UP(_num, _mul)
Round up - Works in all cases, but is slower.
Definition math.h:206
long int ssize_t
unsigned char uint8_t
unsigned long int size_t
#define fr_assert(_expr)
Definition rad_assert.h:37
static char const * name
return count
Definition module.c:155
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
void ** talloc_array_null_terminate(void **array)
Add a NULL pointer to an array of pointers.
Definition talloc.c:850
static int _talloc_destructor_fire(fr_talloc_destructor_t *d)
Called with the fire_ctx is freed.
Definition talloc.c:64
char * talloc_bstrdup(TALLOC_CTX *ctx, char const *in)
Binary safe strdup function.
Definition talloc.c:589
static int _talloc_link_ctx_free(UNUSED void *parent, void *child)
Definition talloc.c:149
static TALLOC_CTX * global_ctx
Definition talloc.c:32
static int _autofree_on_exit(void *af)
Callback to free the autofree ctx on global exit.
Definition talloc.c:874
char * talloc_typed_vasprintf(TALLOC_CTX *ctx, char const *fmt, va_list ap)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition talloc.c:572
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.
Definition talloc.c:96
char * talloc_typed_strdup_buffer(TALLOC_CTX *ctx, char const *p)
Call talloc_strndup, setting the type on the new chunk correctly.
Definition talloc.c:495
ssize_t talloc_hdr_size(void)
Calculate the size of the talloc chunk header.
Definition talloc.c:271
TALLOC_CTX * talloc_autofree_context_global(void)
Definition talloc.c:888
static int _autofree_thread_local_destructor(TALLOC_CTX *af)
Ensures in the autofree ctx is manually freed, things don't explode atexit.
Definition talloc.c:908
char * talloc_buffer_append_variadic_buffer(TALLOC_CTX *ctx, char *to, int argc,...)
Concatenate to + ...
Definition talloc.c:717
void * _talloc_realloc_zero(const void *ctx, void *ptr, size_t elem_size, unsigned count, const char *name)
Version of talloc_realloc which zeroes out freshly allocated memory.
Definition talloc.c:418
char * talloc_bstr_realloc(TALLOC_CTX *ctx, char *in, size_t inlen)
Trim a bstr (char) buffer.
Definition talloc.c:681
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition talloc.c:545
TALLOC_CTX * talloc_aligned_array(TALLOC_CTX *ctx, void **start, size_t alignment, size_t size)
Return a page aligned talloc memory array.
Definition talloc.c:196
static int _talloc_destructor_disarm(fr_talloc_destructor_disarm_t *ds)
Called when the disarm_ctx ctx is freed.
Definition talloc.c:77
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.
Definition talloc.c:167
static void _talloc_hdr_size(void)
Calculate the size of talloc chunk headers, once, on startup.
Definition talloc.c:228
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.
Definition talloc.c:445
static _Thread_local TALLOC_CTX * thread_local_ctx
Definition talloc.c:33
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
Definition talloc.c:617
static size_t t_hdr_size
How big the chunk header is.
Definition talloc.c:223
void * talloc_null_ctx(void)
Retrieve the current talloc NULL ctx.
Definition talloc.c:49
TALLOC_CTX * talloc_page_aligned_pool(TALLOC_CTX *ctx, void **start, size_t *end_len, unsigned int headers, size_t size)
Return a page aligned talloc memory pool.
Definition talloc.c:308
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
Definition talloc.c:470
void talloc_free_data(void *data)
A wrapper that can be passed to tree or hash alloc functions that take a fr_free_t.
Definition talloc.c:37
int talloc_decrease_ref_count(void const *ptr)
Decrease the reference count on a ptr.
Definition talloc.c:817
char * talloc_typed_strndup(TALLOC_CTX *ctx, char const *p, size_t len)
Call talloc_strndup, setting the type on the new chunk correctly.
Definition talloc.c:521
TALLOC_CTX * talloc_autofree_context_thread_local(void)
Get a thread-safe autofreed ctx that will be freed when the thread or process exits.
Definition talloc.c:920
char * talloc_bstr_append(TALLOC_CTX *ctx, char *to, char const *from, size_t from_len)
Append a bstr to a bstr.
Definition talloc.c:645
void talloc_destructor_disarm(fr_talloc_destructor_t *d)
Disarm a destructor and free all memory allocated in the trigger ctxs.
Definition talloc.c:138
int talloc_memcmp_bstr(char const *a, char const *b)
Compares two talloced char arrays with memcmp.
Definition talloc.c:793
static int _autofree_global_destructor(TALLOC_CTX *af)
Ensures in the autofree ctx is manually freed, things don't explode atexit.
Definition talloc.c:883
#define talloc_strndup(_ctx, _str, _len)
Definition talloc.h:143
fr_talloc_free_func_t func
Free function.
Definition talloc.h:89
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
Definition talloc.h:120
fr_talloc_destructor_t * d
Destructor to disarm.
Definition talloc.h:99
void * uctx
uctx to pass to free function.
Definition talloc.h:90
void * fire
Parent chunk.
Definition talloc.h:87
int(* fr_talloc_free_func_t)(void *fire_ctx, void *uctx)
Definition talloc.h:77
fr_talloc_destructor_disarm_t * ds
Chunk to free.
Definition talloc.h:91
#define talloc_strdup(_ctx, _str)
Definition talloc.h:142
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
Definition talloc.h:136
Structure to record a destructor to disarm if a child talloc chunk is freed.
Definition talloc.h:98
Structure to record a destructor operation on a specific talloc chunk.
Definition talloc.h:86
static fr_slen_t parent
Definition pair.h:858
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
static fr_slen_t data
Definition value.h:1340
static size_t char fr_sbuff_t size_t inlen
Definition value.h:1030
static size_t char ** out
Definition value.h:1030