Coverage Report

Created: 2023-12-08 06:56

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