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