1 /*
2 Samba Unix SMB/CIFS implementation.
3
4 Samba trivial allocation library - new interface
5
6 NOTE: Please read talloc_guide.txt for full documentation
7
8 Copyright (C) Andrew Tridgell 2004
9
10 ** NOTE! The following LGPL license applies to the talloc
11 ** library. This does NOT imply that all of Samba is released
12 ** under the LGPL
13
14 This library is free software; you can redistribute it and/or
15 modify it under the terms of the GNU Lesser General Public
16 License as published by the Free Software Foundation; either
17 version 2 of the License, or (at your option) any later version.
18
19 This library is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 Lesser General Public License for more details.
23
24 You should have received a copy of the GNU Lesser General Public
25 License along with this library; If not, see <http://www.gnu.org/licenses/>.
26 */
27
28 /*
29 inspired by http://swapped.cc/halloc/
30 */
31
32 #ifdef _SAMBA_BUILD_
33 #include "includes.h"
34 #if ((SAMBA_VERSION_MAJOR==3)&&(SAMBA_VERSION_MINOR<9))
35 /* This is to circumvent SAMBA3's paranoid malloc checker. Here in this file
36 * we trust ourselves... */
37 #ifdef malloc
38 #undef malloc
39 #endif
40 #ifdef realloc
41 #undef realloc
42 #endif
43 #endif
44 #else
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <stdarg.h>
49 #include <stdint.h>
50 #include "talloc.h"
51 /* assume a modern system */
52 #define HAVE_VA_COPY
53 #endif
54
55 /* use this to force every realloc to change the pointer, to stress test
56 code that might not cope */
57 #define ALWAYS_REALLOC 0
58
59
60 #define MAX_TALLOC_SIZE 0x10000000
61 #define TALLOC_MAGIC 0xe814ec70
62 #define TALLOC_FLAG_FREE 0x01
63 #define TALLOC_FLAG_LOOP 0x02
64 #define TALLOC_MAGIC_REFERENCE ((const char *)1)
65
66 /* by default we abort when given a bad pointer (such as when talloc_free() is called
67 on a pointer that came from malloc() */
68 #ifndef TALLOC_ABORT
69 #define TALLOC_ABORT(reason) abort()
70 #endif
71
72 #ifndef discard_const_p
73 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
74 # define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
75 #else
76 # define discard_const_p(type, ptr) ((type *)(ptr))
77 #endif
78 #endif
79
80 /* this null_context is only used if talloc_enable_leak_report() or
81 talloc_enable_leak_report_full() is called, otherwise it remains
82 NULL
83 */
84 static const void *null_context;
85 static void *cleanup_context;
86
87
88 struct talloc_reference_handle {
89 struct talloc_reference_handle *next, *prev;
90 void *ptr;
91 };
92
93 typedef int (*talloc_destructor_t)(void *);
94
95 struct talloc_chunk {
96 struct talloc_chunk *next, *prev;
97 struct talloc_chunk *parent, *child;
98 struct talloc_reference_handle *refs;
99 unsigned int null_refs; /* references from null_context */
100 talloc_destructor_t destructor;
101 const char *name;
102 size_t size;
103 unsigned flags;
104 };
105
106 /* 16 byte alignment seems to keep everyone happy */
107 #define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15)
108 #define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc))
109
110 /* panic if we get a bad magic value */
talloc_chunk_from_ptr(const void * ptr)111 static struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
112 {
113 const char *pp = ptr;
114 struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE);
115 if ((tc->flags & ~0xF) != TALLOC_MAGIC) {
116 TALLOC_ABORT("Bad talloc magic value - unknown value");
117 }
118 if (tc->flags & TALLOC_FLAG_FREE) {
119 TALLOC_ABORT("Bad talloc magic value - double free");
120 }
121 return tc;
122 }
123
124 /* hook into the front of the list */
125 #define _TLIST_ADD(list, p) \
126 do { \
127 if (!(list)) { \
128 (list) = (p); \
129 (p)->next = (p)->prev = NULL; \
130 } else { \
131 (list)->prev = (p); \
132 (p)->next = (list); \
133 (p)->prev = NULL; \
134 (list) = (p); \
135 }\
136 } while (0)
137
138 /* remove an element from a list - element doesn't have to be in list. */
139 #define _TLIST_REMOVE(list, p) \
140 do { \
141 if ((p) == (list)) { \
142 (list) = (p)->next; \
143 if (list) (list)->prev = NULL; \
144 } else { \
145 if ((p)->prev) (p)->prev->next = (p)->next; \
146 if ((p)->next) (p)->next->prev = (p)->prev; \
147 } \
148 if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
149 } while (0)
150
151
152 /*
153 return the parent chunk of a pointer
154 */
talloc_parent_chunk(const void * ptr)155 static struct talloc_chunk *talloc_parent_chunk(const void *ptr)
156 {
157 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
158 while (tc->prev) tc=tc->prev;
159 return tc->parent;
160 }
161
talloc_parent(const void * ptr)162 void *talloc_parent(const void *ptr)
163 {
164 struct talloc_chunk *tc = talloc_parent_chunk(ptr);
165 return tc? TC_PTR_FROM_CHUNK(tc) : NULL;
166 }
167
168 /*
169 Allocate a bit of memory as a child of an existing pointer
170 */
_talloc(const void * context,size_t size)171 void *_talloc(const void *context, size_t size)
172 {
173 struct talloc_chunk *tc;
174
175 if (context == NULL) {
176 context = null_context;
177 }
178
179 if (size >= MAX_TALLOC_SIZE) {
180 return NULL;
181 }
182
183 tc = malloc(TC_HDR_SIZE+size);
184 if (tc == NULL) return NULL;
185
186 tc->size = size;
187 tc->flags = TALLOC_MAGIC;
188 tc->destructor = NULL;
189 tc->child = NULL;
190 tc->name = NULL;
191 tc->refs = NULL;
192 tc->null_refs = 0;
193
194 if (context) {
195 struct talloc_chunk *parent = talloc_chunk_from_ptr(context);
196
197 tc->parent = parent;
198
199 if (parent->child) {
200 parent->child->parent = NULL;
201 }
202
203 _TLIST_ADD(parent->child, tc);
204 } else {
205 tc->next = tc->prev = tc->parent = NULL;
206 }
207
208 return TC_PTR_FROM_CHUNK(tc);
209 }
210
211
212 /*
213 setup a destructor to be called on free of a pointer
214 the destructor should return 0 on success, or -1 on failure.
215 if the destructor fails then the free is failed, and the memory can
216 be continued to be used
217 */
talloc_set_destructor(const void * ptr,int (* destructor)(void *))218 void talloc_set_destructor(const void *ptr, int (*destructor)(void *))
219 {
220 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
221 tc->destructor = destructor;
222 }
223
224 /*
225 increase the reference count on a piece of memory.
226 */
talloc_increase_ref_count(const void * ptr)227 void talloc_increase_ref_count(const void *ptr)
228 {
229 struct talloc_chunk *tc;
230 if (ptr == NULL) return;
231
232 tc = talloc_chunk_from_ptr(ptr);
233 tc->null_refs++;
234 }
235
236 /*
237 helper for talloc_reference()
238 */
talloc_reference_destructor(void * ptr)239 static int talloc_reference_destructor(void *ptr)
240 {
241 struct talloc_reference_handle *handle = ptr;
242 struct talloc_chunk *tc1 = talloc_chunk_from_ptr(ptr);
243 struct talloc_chunk *tc2 = talloc_chunk_from_ptr(handle->ptr);
244 if (tc1->destructor != (talloc_destructor_t)-1) {
245 tc1->destructor = NULL;
246 }
247 _TLIST_REMOVE(tc2->refs, handle);
248 talloc_free(handle);
249 return 0;
250 }
251
252 /*
253 make a secondary reference to a pointer, hanging off the given context.
254 the pointer remains valid until both the original caller and this given
255 context are freed.
256
257 the major use for this is when two different structures need to reference the
258 same underlying data, and you want to be able to free the two instances separately,
259 and in either order
260 */
talloc_reference(const void * context,const void * ptr)261 void *talloc_reference(const void *context, const void *ptr)
262 {
263 struct talloc_chunk *tc;
264 struct talloc_reference_handle *handle;
265 if (ptr == NULL) return NULL;
266
267 tc = talloc_chunk_from_ptr(ptr);
268 handle = talloc_named_const(context, sizeof(*handle), TALLOC_MAGIC_REFERENCE);
269
270 if (handle == NULL) return NULL;
271
272 /* note that we hang the destructor off the handle, not the
273 main context as that allows the caller to still setup their
274 own destructor on the context if they want to */
275 talloc_set_destructor(handle, talloc_reference_destructor);
276 handle->ptr = discard_const_p(void, ptr);
277 _TLIST_ADD(tc->refs, handle);
278 return handle->ptr;
279 }
280
281 /*
282 remove a secondary reference to a pointer. This undo's what
283 talloc_reference() has done. The context and pointer arguments
284 must match those given to a talloc_reference()
285 */
talloc_unreference(const void * context,const void * ptr)286 static int talloc_unreference(const void *context, const void *ptr)
287 {
288 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
289 struct talloc_reference_handle *h;
290
291 if (context == NULL) {
292 context = null_context;
293 }
294
295 if ((context == null_context) && tc->null_refs) {
296 tc->null_refs--;
297 return 0;
298 }
299
300 for (h=tc->refs;h;h=h->next) {
301 struct talloc_chunk *p = talloc_parent_chunk(h);
302 if (p == NULL) {
303 if (context == NULL) break;
304 } else if (TC_PTR_FROM_CHUNK(p) == context) {
305 break;
306 }
307 }
308 if (h == NULL) {
309 return -1;
310 }
311
312 talloc_set_destructor(h, NULL);
313 _TLIST_REMOVE(tc->refs, h);
314 talloc_free(h);
315 return 0;
316 }
317
318 /*
319 remove a specific parent context from a pointer. This is a more
320 controlled varient of talloc_free()
321 */
talloc_unlink(const void * context,const void * ptr)322 int talloc_unlink(const void *context, const void *ptr)
323 {
324 struct talloc_chunk *tc_p, *new_p;
325 void *new_parent;
326
327 if (ptr == NULL) {
328 return -1;
329 }
330
331 if (context == NULL) {
332 context = null_context;
333 }
334
335 if (talloc_unreference(context, ptr) == 0) {
336 return 0;
337 }
338
339 if (context == NULL) {
340 if (talloc_parent_chunk(ptr) != NULL) {
341 return -1;
342 }
343 } else {
344 if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) {
345 return -1;
346 }
347 }
348
349 tc_p = talloc_chunk_from_ptr(ptr);
350
351 if (tc_p->refs == NULL) {
352 return talloc_free(ptr);
353 }
354
355 new_p = talloc_parent_chunk(tc_p->refs);
356 if (new_p) {
357 new_parent = TC_PTR_FROM_CHUNK(new_p);
358 } else {
359 new_parent = NULL;
360 }
361
362 if (talloc_unreference(new_parent, ptr) != 0) {
363 return -1;
364 }
365
366 talloc_steal(new_parent, ptr);
367
368 return 0;
369 }
370
371 /*
372 add a name to an existing pointer - va_list version
373 */
374 static void talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
375
talloc_set_name_v(const void * ptr,const char * fmt,va_list ap)376 static void talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
377 {
378 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
379 tc->name = talloc_vasprintf(ptr, fmt, ap);
380 if (tc->name) {
381 talloc_set_name_const(tc->name, ".name");
382 }
383 }
384
385 /*
386 add a name to an existing pointer
387 */
talloc_set_name(const void * ptr,const char * fmt,...)388 void talloc_set_name(const void *ptr, const char *fmt, ...)
389 {
390 va_list ap;
391 va_start(ap, fmt);
392 talloc_set_name_v(ptr, fmt, ap);
393 va_end(ap);
394 }
395
396 /*
397 more efficient way to add a name to a pointer - the name must point to a
398 true string constant
399 */
talloc_set_name_const(const void * ptr,const char * name)400 void talloc_set_name_const(const void *ptr, const char *name)
401 {
402 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
403 tc->name = name;
404 }
405
406 /*
407 create a named talloc pointer. Any talloc pointer can be named, and
408 talloc_named() operates just like talloc() except that it allows you
409 to name the pointer.
410 */
talloc_named(const void * context,size_t size,const char * fmt,...)411 void *talloc_named(const void *context, size_t size, const char *fmt, ...)
412 {
413 va_list ap;
414 void *ptr;
415
416 ptr = _talloc(context, size);
417 if (ptr == NULL) return NULL;
418
419 va_start(ap, fmt);
420 talloc_set_name_v(ptr, fmt, ap);
421 va_end(ap);
422
423 return ptr;
424 }
425
426 /*
427 create a named talloc pointer. Any talloc pointer can be named, and
428 talloc_named() operates just like talloc() except that it allows you
429 to name the pointer.
430 */
talloc_named_const(const void * context,size_t size,const char * name)431 void *talloc_named_const(const void *context, size_t size, const char *name)
432 {
433 void *ptr;
434
435 ptr = _talloc(context, size);
436 if (ptr == NULL) {
437 return NULL;
438 }
439
440 talloc_set_name_const(ptr, name);
441
442 return ptr;
443 }
444
445 /*
446 return the name of a talloc ptr, or "UNNAMED"
447 */
talloc_get_name(const void * ptr)448 const char *talloc_get_name(const void *ptr)
449 {
450 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
451 if (tc->name == TALLOC_MAGIC_REFERENCE) {
452 return ".reference";
453 }
454 if (tc->name) {
455 return tc->name;
456 }
457 return "UNNAMED";
458 }
459
460
461 /*
462 check if a pointer has the given name. If it does, return the pointer,
463 otherwise return NULL
464 */
talloc_check_name(const void * ptr,const char * name)465 void *talloc_check_name(const void *ptr, const char *name)
466 {
467 const char *pname;
468 if (ptr == NULL) return NULL;
469 pname = talloc_get_name(ptr);
470 if (pname == name || strcmp(pname, name) == 0) {
471 return discard_const_p(void, ptr);
472 }
473 return NULL;
474 }
475
476
477 /*
478 this is for compatibility with older versions of talloc
479 */
talloc_init(const char * fmt,...)480 void *talloc_init(const char *fmt, ...)
481 {
482 va_list ap;
483 void *ptr;
484
485 talloc_enable_null_tracking();
486
487 ptr = _talloc(NULL, 0);
488 if (ptr == NULL) return NULL;
489
490 va_start(ap, fmt);
491 talloc_set_name_v(ptr, fmt, ap);
492 va_end(ap);
493
494 return ptr;
495 }
496
497 /*
498 this is a replacement for the Samba3 talloc_destroy_pool functionality. It
499 should probably not be used in new code. It's in here to keep the talloc
500 code consistent across Samba 3 and 4.
501 */
talloc_free_children(const void * ptr)502 static void talloc_free_children(const void *ptr)
503 {
504 struct talloc_chunk *tc;
505
506 if (ptr == NULL) {
507 return;
508 }
509
510 tc = talloc_chunk_from_ptr(ptr);
511
512 while (tc->child) {
513 /* we need to work out who will own an abandoned child
514 if it cannot be freed. In priority order, the first
515 choice is owner of any remaining reference to this
516 pointer, the second choice is our parent, and the
517 final choice is the null context. */
518 void *child = TC_PTR_FROM_CHUNK(tc->child);
519 const void *new_parent = null_context;
520 if (tc->child->refs) {
521 struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
522 if (p) new_parent = TC_PTR_FROM_CHUNK(p);
523 }
524 if (talloc_free(child) == -1) {
525 if (new_parent == null_context) {
526 struct talloc_chunk *p = talloc_parent_chunk(ptr);
527 if (p) new_parent = TC_PTR_FROM_CHUNK(p);
528 }
529 talloc_steal(new_parent, child);
530 }
531 }
532 }
533
534 /*
535 free a talloc pointer. This also frees all child pointers of this
536 pointer recursively
537
538 return 0 if the memory is actually freed, otherwise -1. The memory
539 will not be freed if the ref_count is > 1 or the destructor (if
540 any) returns non-zero
541 */
talloc_free(const void * ptr)542 int talloc_free(const void *ptr)
543 {
544 int saved_errno = errno;
545 struct talloc_chunk *tc;
546
547 if (ptr == NULL) {
548 goto err;
549 }
550
551 tc = talloc_chunk_from_ptr(ptr);
552
553 if (tc->null_refs) {
554 tc->null_refs--;
555 goto err;
556 }
557
558 if (tc->refs) {
559 talloc_reference_destructor(tc->refs);
560 goto err;
561 }
562
563 if (tc->flags & TALLOC_FLAG_LOOP) {
564 /* we have a free loop - stop looping */
565 goto success;
566 }
567
568 if (tc->destructor) {
569 talloc_destructor_t d = tc->destructor;
570 if (d == (talloc_destructor_t)-1) {
571 goto err;
572 }
573 tc->destructor = (talloc_destructor_t)-1;
574
575 /* The destructor needs to be able to change the object! */
576 if (d((void *)ptr) == -1) {
577 tc->destructor = d;
578 goto err;
579 }
580 tc->destructor = NULL;
581 }
582
583 tc->flags |= TALLOC_FLAG_LOOP;
584
585 talloc_free_children(ptr);
586
587 if (tc->parent) {
588 _TLIST_REMOVE(tc->parent->child, tc);
589 if (tc->parent->child) {
590 tc->parent->child->parent = tc->parent;
591 }
592 } else {
593 if (tc->prev) tc->prev->next = tc->next;
594 if (tc->next) tc->next->prev = tc->prev;
595 }
596
597 tc->flags |= TALLOC_FLAG_FREE;
598
599 free(tc);
600 success:
601 errno = saved_errno;
602 return 0;
603
604 err:
605 errno = saved_errno;
606 return -1;
607 }
608
609 /*
610 A talloc version of realloc. The context argument is only used if
611 ptr is NULL
612 */
_talloc_realloc(const void * context,void * ptr,size_t size,const char * name)613 void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name)
614 {
615 struct talloc_chunk *tc;
616 void *new_ptr;
617
618 /* size zero is equivalent to free() */
619 if (size == 0) {
620 talloc_free(ptr);
621 return NULL;
622 }
623
624 if (size >= MAX_TALLOC_SIZE) {
625 return NULL;
626 }
627
628 /* realloc(NULL) is equavalent to malloc() */
629 if (ptr == NULL) {
630 return talloc_named_const(context, size, name);
631 }
632
633 tc = talloc_chunk_from_ptr(ptr);
634
635 /* don't allow realloc on referenced pointers */
636 if (tc->refs) {
637 return NULL;
638 }
639
640 /* by resetting magic we catch users of the old memory */
641 tc->flags |= TALLOC_FLAG_FREE;
642
643 #if ALWAYS_REALLOC
644 new_ptr = malloc(size + TC_HDR_SIZE);
645 if (new_ptr) {
646 memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE);
647 free(tc);
648 }
649 #else
650 new_ptr = realloc(tc, size + TC_HDR_SIZE);
651 #endif
652 if (!new_ptr) {
653 tc->flags &= ~TALLOC_FLAG_FREE;
654 return NULL;
655 }
656
657 tc = new_ptr;
658 tc->flags &= ~TALLOC_FLAG_FREE;
659 if (tc->parent) {
660 tc->parent->child = new_ptr;
661 }
662 if (tc->child) {
663 tc->child->parent = new_ptr;
664 }
665
666 if (tc->prev) {
667 tc->prev->next = tc;
668 }
669 if (tc->next) {
670 tc->next->prev = tc;
671 }
672
673 tc->size = size;
674 talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
675
676 return TC_PTR_FROM_CHUNK(tc);
677 }
678
679 /*
680 move a lump of memory from one talloc context to another return the
681 ptr on success, or NULL if it could not be transferred.
682 passing NULL as ptr will always return NULL with no side effects.
683 */
talloc_steal(const void * new_ctx,const void * ptr)684 void *talloc_steal(const void *new_ctx, const void *ptr)
685 {
686 struct talloc_chunk *tc, *new_tc;
687
688 if (!ptr) {
689 return NULL;
690 }
691
692 if (new_ctx == NULL) {
693 new_ctx = null_context;
694 }
695
696 tc = talloc_chunk_from_ptr(ptr);
697
698 if (new_ctx == NULL) {
699 if (tc->parent) {
700 _TLIST_REMOVE(tc->parent->child, tc);
701 if (tc->parent->child) {
702 tc->parent->child->parent = tc->parent;
703 }
704 } else {
705 if (tc->prev) tc->prev->next = tc->next;
706 if (tc->next) tc->next->prev = tc->prev;
707 }
708
709 tc->parent = tc->next = tc->prev = NULL;
710 return discard_const_p(void, ptr);
711 }
712
713 new_tc = talloc_chunk_from_ptr(new_ctx);
714
715 if (tc == new_tc) {
716 return discard_const_p(void, ptr);
717 }
718
719 if (tc->parent) {
720 _TLIST_REMOVE(tc->parent->child, tc);
721 if (tc->parent->child) {
722 tc->parent->child->parent = tc->parent;
723 }
724 } else {
725 if (tc->prev) tc->prev->next = tc->next;
726 if (tc->next) tc->next->prev = tc->prev;
727 }
728
729 tc->parent = new_tc;
730 if (new_tc->child) new_tc->child->parent = NULL;
731 _TLIST_ADD(new_tc->child, tc);
732
733 return discard_const_p(void, ptr);
734 }
735
736 /*
737 return the total size of a talloc pool (subtree)
738 */
talloc_total_size(const void * ptr)739 off_t talloc_total_size(const void *ptr)
740 {
741 off_t total = 0;
742 struct talloc_chunk *c, *tc;
743
744 if (ptr == NULL) {
745 ptr = null_context;
746 }
747 if (ptr == NULL) {
748 return 0;
749 }
750
751 tc = talloc_chunk_from_ptr(ptr);
752
753 if (tc->flags & TALLOC_FLAG_LOOP) {
754 return 0;
755 }
756
757 tc->flags |= TALLOC_FLAG_LOOP;
758
759 total = tc->size;
760 for (c=tc->child;c;c=c->next) {
761 total += talloc_total_size(TC_PTR_FROM_CHUNK(c));
762 }
763
764 tc->flags &= ~TALLOC_FLAG_LOOP;
765
766 return total;
767 }
768
769 /*
770 return the total number of blocks in a talloc pool (subtree)
771 */
talloc_total_blocks(const void * ptr)772 off_t talloc_total_blocks(const void *ptr)
773 {
774 off_t total = 0;
775 struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
776
777 if (tc->flags & TALLOC_FLAG_LOOP) {
778 return 0;
779 }
780
781 tc->flags |= TALLOC_FLAG_LOOP;
782
783 total++;
784 for (c=tc->child;c;c=c->next) {
785 total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c));
786 }
787
788 tc->flags &= ~TALLOC_FLAG_LOOP;
789
790 return total;
791 }
792
793 /*
794 return the number of external references to a pointer
795 */
talloc_reference_count(const void * ptr)796 static int talloc_reference_count(const void *ptr)
797 {
798 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
799 struct talloc_reference_handle *h;
800 int ret = 0;
801
802 for (h=tc->refs;h;h=h->next) {
803 ret++;
804 }
805 return ret;
806 }
807
808 /*
809 report on memory usage by all children of a pointer, giving a full tree view
810 */
talloc_report_depth(const void * ptr,FILE * f,int depth)811 void talloc_report_depth(const void *ptr, FILE *f, int depth)
812 {
813 struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
814
815 if (tc->flags & TALLOC_FLAG_LOOP) {
816 return;
817 }
818
819 tc->flags |= TALLOC_FLAG_LOOP;
820
821 for (c=tc->child;c;c=c->next) {
822 if (c->name == TALLOC_MAGIC_REFERENCE) {
823 struct talloc_reference_handle *handle = TC_PTR_FROM_CHUNK(c);
824 const char *name2 = talloc_get_name(handle->ptr);
825 fprintf(f, "%*sreference to: %s\n", depth*4, "", name2);
826 } else {
827 const char *name = talloc_get_name(TC_PTR_FROM_CHUNK(c));
828 fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n",
829 depth*4, "",
830 name,
831 (unsigned long)talloc_total_size(TC_PTR_FROM_CHUNK(c)),
832 (unsigned long)talloc_total_blocks(TC_PTR_FROM_CHUNK(c)),
833 talloc_reference_count(TC_PTR_FROM_CHUNK(c)));
834 talloc_report_depth(TC_PTR_FROM_CHUNK(c), f, depth+1);
835 }
836 }
837 tc->flags &= ~TALLOC_FLAG_LOOP;
838 }
839
840 /*
841 report on memory usage by all children of a pointer, giving a full tree view
842 */
talloc_report_full(const void * ptr,FILE * f)843 void talloc_report_full(const void *ptr, FILE *f)
844 {
845 if (ptr == NULL) {
846 ptr = null_context;
847 }
848 if (ptr == NULL) return;
849
850 fprintf(f,"full talloc report on '%s' (total %lu bytes in %lu blocks)\n",
851 talloc_get_name(ptr),
852 (unsigned long)talloc_total_size(ptr),
853 (unsigned long)talloc_total_blocks(ptr));
854
855 talloc_report_depth(ptr, f, 1);
856 fflush(f);
857 }
858
859 /*
860 report on memory usage by all children of a pointer
861 */
talloc_report(const void * ptr,FILE * f)862 void talloc_report(const void *ptr, FILE *f)
863 {
864 struct talloc_chunk *c, *tc;
865
866 if (ptr == NULL) {
867 ptr = null_context;
868 }
869 if (ptr == NULL) return;
870
871 fprintf(f,"talloc report on '%s' (total %lu bytes in %lu blocks)\n",
872 talloc_get_name(ptr),
873 (unsigned long)talloc_total_size(ptr),
874 (unsigned long)talloc_total_blocks(ptr));
875
876 tc = talloc_chunk_from_ptr(ptr);
877
878 for (c=tc->child;c;c=c->next) {
879 fprintf(f, "\t%-30s contains %6lu bytes in %3lu blocks\n",
880 talloc_get_name(TC_PTR_FROM_CHUNK(c)),
881 (unsigned long)talloc_total_size(TC_PTR_FROM_CHUNK(c)),
882 (unsigned long)talloc_total_blocks(TC_PTR_FROM_CHUNK(c)));
883 }
884 fflush(f);
885 }
886
887 /*
888 report on any memory hanging off the null context
889 */
talloc_report_null(void)890 static void talloc_report_null(void)
891 {
892 if (talloc_total_size(null_context) != 0) {
893 talloc_report(null_context, stderr);
894 }
895 }
896
897 /*
898 report on any memory hanging off the null context
899 */
talloc_report_null_full(void)900 static void talloc_report_null_full(void)
901 {
902 if (talloc_total_size(null_context) != 0) {
903 talloc_report_full(null_context, stderr);
904 }
905 }
906
907 /*
908 enable tracking of the NULL context
909 */
talloc_enable_null_tracking(void)910 void talloc_enable_null_tracking(void)
911 {
912 if (null_context == NULL) {
913 null_context = talloc_named_const(NULL, 0, "null_context");
914 }
915 }
916
917 #ifdef _SAMBA_BUILD_
918 /* Ugly calls to Samba-specific sprintf_append... JRA. */
919
920 /*
921 report on memory usage by all children of a pointer, giving a full tree view
922 */
talloc_report_depth_str(const void * ptr,char ** pps,ssize_t * plen,size_t * pbuflen,int depth)923 static void talloc_report_depth_str(const void *ptr, char **pps, ssize_t *plen, size_t *pbuflen, int depth)
924 {
925 struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
926
927 if (tc->flags & TALLOC_FLAG_LOOP) {
928 return;
929 }
930
931 tc->flags |= TALLOC_FLAG_LOOP;
932
933 for (c=tc->child;c;c=c->next) {
934 if (c->name == TALLOC_MAGIC_REFERENCE) {
935 struct talloc_reference_handle *handle = TC_PTR_FROM_CHUNK(c);
936 const char *name2 = talloc_get_name(handle->ptr);
937
938 sprintf_append(NULL, pps, plen, pbuflen,
939 "%*sreference to: %s\n", depth*4, "", name2);
940
941 } else {
942 const char *name = talloc_get_name(TC_PTR_FROM_CHUNK(c));
943
944 sprintf_append(NULL, pps, plen, pbuflen,
945 "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n",
946 depth*4, "",
947 name,
948 (unsigned long)talloc_total_size(TC_PTR_FROM_CHUNK(c)),
949 (unsigned long)talloc_total_blocks(TC_PTR_FROM_CHUNK(c)),
950 talloc_reference_count(TC_PTR_FROM_CHUNK(c)));
951
952 talloc_report_depth_str(TC_PTR_FROM_CHUNK(c), pps, plen, pbuflen, depth+1);
953 }
954 }
955 tc->flags &= ~TALLOC_FLAG_LOOP;
956 }
957
958 /*
959 report on memory usage by all children of a pointer
960 */
talloc_describe_all(void)961 char *talloc_describe_all(void)
962 {
963 ssize_t len = 0;
964 size_t buflen = 512;
965 char *s = NULL;
966
967 if (null_context == NULL) {
968 return NULL;
969 }
970
971 sprintf_append(NULL, &s, &len, &buflen,
972 "full talloc report on '%s' (total %lu bytes in %lu blocks)\n",
973 talloc_get_name(null_context),
974 (unsigned long)talloc_total_size(null_context),
975 (unsigned long)talloc_total_blocks(null_context));
976
977 if (!s) {
978 return NULL;
979 }
980 talloc_report_depth_str(null_context, &s, &len, &buflen, 1);
981 return s;
982 }
983 #endif
984
985 /*
986 enable leak reporting on exit
987 */
talloc_enable_leak_report(void)988 void talloc_enable_leak_report(void)
989 {
990 talloc_enable_null_tracking();
991 atexit(talloc_report_null);
992 }
993
994 /*
995 enable full leak reporting on exit
996 */
talloc_enable_leak_report_full(void)997 void talloc_enable_leak_report_full(void)
998 {
999 talloc_enable_null_tracking();
1000 atexit(talloc_report_null_full);
1001 }
1002
1003 /*
1004 talloc and zero memory.
1005 */
_talloc_zero(const void * ctx,size_t size,const char * name)1006 void *_talloc_zero(const void *ctx, size_t size, const char *name)
1007 {
1008 void *p = talloc_named_const(ctx, size, name);
1009
1010 if (p) {
1011 memset(p, '\0', size);
1012 }
1013
1014 return p;
1015 }
1016
1017
1018 /*
1019 memdup with a talloc.
1020 */
_talloc_memdup(const void * t,const void * p,size_t size,const char * name)1021 void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name)
1022 {
1023 void *newp = talloc_named_const(t, size, name);
1024
1025 if (newp) {
1026 memcpy(newp, p, size);
1027 }
1028
1029 return newp;
1030 }
1031
1032 /*
1033 strdup with a talloc
1034 */
talloc_strdup(const void * t,const char * p)1035 char *talloc_strdup(const void *t, const char *p)
1036 {
1037 char *ret;
1038 if (!p) {
1039 return NULL;
1040 }
1041 ret = talloc_memdup(t, p, strlen(p) + 1);
1042 if (ret) {
1043 talloc_set_name_const(ret, ret);
1044 }
1045 return ret;
1046 }
1047
1048 /*
1049 append to a talloced string
1050 */
talloc_append_string(const void * t,char * orig,const char * append)1051 char *talloc_append_string(const void *t, char *orig, const char *append)
1052 {
1053 char *ret;
1054 size_t olen = strlen(orig);
1055 size_t alenz;
1056
1057 if (!append)
1058 return orig;
1059
1060 alenz = strlen(append) + 1;
1061
1062 ret = talloc_realloc(t, orig, char, olen + alenz);
1063 if (!ret)
1064 return NULL;
1065
1066 /* append the string with the trailing \0 */
1067 memcpy(&ret[olen], append, alenz);
1068
1069 return ret;
1070 }
1071
1072 /*
1073 strndup with a talloc
1074 */
talloc_strndup(const void * t,const char * p,size_t n)1075 char *talloc_strndup(const void *t, const char *p, size_t n)
1076 {
1077 size_t len;
1078 char *ret;
1079
1080 for (len=0; len<n && p[len]; len++) ;
1081
1082 ret = _talloc(t, len + 1);
1083 if (!ret) { return NULL; }
1084 memcpy(ret, p, len);
1085 ret[len] = 0;
1086 talloc_set_name_const(ret, ret);
1087 return ret;
1088 }
1089
1090 #ifndef VA_COPY
1091 #ifdef HAVE_VA_COPY
1092 #define VA_COPY(dest, src) va_copy(dest, src)
1093 #elif defined(HAVE___VA_COPY)
1094 #define VA_COPY(dest, src) __va_copy(dest, src)
1095 #else
1096 #define VA_COPY(dest, src) (dest) = (src)
1097 #endif
1098 #endif
1099
talloc_vasprintf(const void * t,const char * fmt,va_list ap)1100 char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
1101 {
1102 int len;
1103 char *ret;
1104 va_list ap2;
1105 char c;
1106
1107 VA_COPY(ap2, ap);
1108
1109 /* this call looks strange, but it makes it work on older solaris boxes */
1110 if ((len = vsnprintf(&c, 1, fmt, ap2)) < 0) {
1111 va_end(ap2);
1112 return NULL;
1113 }
1114 va_end(ap2);
1115
1116 ret = _talloc(t, len+1);
1117 if (ret) {
1118 VA_COPY(ap2, ap);
1119 vsnprintf(ret, len+1, fmt, ap2);
1120 va_end(ap2);
1121 talloc_set_name_const(ret, ret);
1122 }
1123
1124 return ret;
1125 }
1126
1127
1128 /*
1129 Perform string formatting, and return a pointer to newly allocated
1130 memory holding the result, inside a memory pool.
1131 */
talloc_asprintf(const void * t,const char * fmt,...)1132 char *talloc_asprintf(const void *t, const char *fmt, ...)
1133 {
1134 va_list ap;
1135 char *ret;
1136
1137 va_start(ap, fmt);
1138 ret = talloc_vasprintf(t, fmt, ap);
1139 va_end(ap);
1140 return ret;
1141 }
1142
1143
1144 /**
1145 * Realloc @p s to append the formatted result of @p fmt and @p ap,
1146 * and return @p s, which may have moved. Good for gradually
1147 * accumulating output into a string buffer.
1148 **/
1149
1150 static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
1151
talloc_vasprintf_append(char * s,const char * fmt,va_list ap)1152 static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
1153 {
1154 struct talloc_chunk *tc;
1155 int len, s_len;
1156 va_list ap2;
1157
1158 if (s == NULL) {
1159 return talloc_vasprintf(NULL, fmt, ap);
1160 }
1161
1162 tc = talloc_chunk_from_ptr(s);
1163
1164 VA_COPY(ap2, ap);
1165
1166 s_len = tc->size - 1;
1167 if ((len = vsnprintf(NULL, 0, fmt, ap2)) <= 0) {
1168 /* Either the vsnprintf failed or the format resulted in
1169 * no characters being formatted. In the former case, we
1170 * ought to return NULL, in the latter we ought to return
1171 * the original string. Most current callers of this
1172 * function expect it to never return NULL.
1173 */
1174 va_end(ap2);
1175 return s;
1176 }
1177 va_end(ap2);
1178
1179 s = talloc_realloc(NULL, s, char, s_len + len+1);
1180 if (!s) return NULL;
1181
1182 VA_COPY(ap2, ap);
1183
1184 vsnprintf(s+s_len, len+1, fmt, ap2);
1185 va_end(ap2);
1186 talloc_set_name_const(s, s);
1187
1188 return s;
1189 }
1190
1191 /*
1192 Realloc @p s to append the formatted result of @p fmt and return @p
1193 s, which may have moved. Good for gradually accumulating output
1194 into a string buffer.
1195 */
talloc_asprintf_append(char * s,const char * fmt,...)1196 char *talloc_asprintf_append(char *s, const char *fmt, ...)
1197 {
1198 va_list ap;
1199
1200 va_start(ap, fmt);
1201 s = talloc_vasprintf_append(s, fmt, ap);
1202 va_end(ap);
1203 return s;
1204 }
1205
1206 /*
1207 alloc an array, checking for integer overflow in the array size
1208 */
_talloc_array(const void * ctx,size_t el_size,unsigned count,const char * name)1209 void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
1210 {
1211 if (count >= MAX_TALLOC_SIZE/el_size) {
1212 return NULL;
1213 }
1214 return talloc_named_const(ctx, el_size * count, name);
1215 }
1216
1217 /*
1218 alloc an zero array, checking for integer overflow in the array size
1219 */
_talloc_zero_array(const void * ctx,size_t el_size,unsigned count,const char * name)1220 void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name)
1221 {
1222 if (count >= MAX_TALLOC_SIZE/el_size) {
1223 return NULL;
1224 }
1225 return _talloc_zero(ctx, el_size * count, name);
1226 }
1227
1228
1229 /*
1230 realloc an array, checking for integer overflow in the array size
1231 */
_talloc_realloc_array(const void * ctx,void * ptr,size_t el_size,unsigned count,const char * name)1232 void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
1233 {
1234 if (count >= MAX_TALLOC_SIZE/el_size) {
1235 return NULL;
1236 }
1237 return _talloc_realloc(ctx, ptr, el_size * count, name);
1238 }
1239
1240 /*
1241 a function version of talloc_realloc(), so it can be passed as a function pointer
1242 to libraries that want a realloc function (a realloc function encapsulates
1243 all the basic capabilities of an allocation library, which is why this is useful)
1244 */
talloc_realloc_fn(const void * context,void * ptr,size_t size)1245 void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
1246 {
1247 return _talloc_realloc(context, ptr, size, NULL);
1248 }
1249
1250
talloc_autofree(void)1251 static void talloc_autofree(void)
1252 {
1253 talloc_free(cleanup_context);
1254 cleanup_context = NULL;
1255 }
1256
1257 /*
1258 return a context which will be auto-freed on exit
1259 this is useful for reducing the noise in leak reports
1260 */
talloc_autofree_context(void)1261 void *talloc_autofree_context(void)
1262 {
1263 if (cleanup_context == NULL) {
1264 cleanup_context = talloc_named_const(NULL, 0, "autofree_context");
1265 atexit(talloc_autofree);
1266 }
1267 return cleanup_context;
1268 }
1269
talloc_get_size(const void * context)1270 size_t talloc_get_size(const void *context)
1271 {
1272 struct talloc_chunk *tc;
1273
1274 if (context == NULL)
1275 return 0;
1276
1277 tc = talloc_chunk_from_ptr(context);
1278
1279 return tc->size;
1280 }
1281
1282 /*
1283 find a parent of this context that has the given name, if any
1284 */
talloc_find_parent_byname(const void * context,const char * name)1285 void *talloc_find_parent_byname(const void *context, const char *name)
1286 {
1287 struct talloc_chunk *tc;
1288
1289 if (context == NULL) {
1290 return NULL;
1291 }
1292
1293 tc = talloc_chunk_from_ptr(context);
1294 while (tc) {
1295 if (tc->name && strcmp(tc->name, name) == 0) {
1296 return TC_PTR_FROM_CHUNK(tc);
1297 }
1298 while (tc && tc->prev) tc = tc->prev;
1299 tc = tc->parent;
1300 }
1301 return NULL;
1302 }
1303
1304 /*
1305 show the parentage of a context
1306 */
talloc_show_parents(const void * context,FILE * file)1307 void talloc_show_parents(const void *context, FILE *file)
1308 {
1309 struct talloc_chunk *tc;
1310
1311 if (context == NULL) {
1312 fprintf(file, "talloc no parents for NULL\n");
1313 return;
1314 }
1315
1316 tc = talloc_chunk_from_ptr(context);
1317 fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
1318 while (tc) {
1319 fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)));
1320 while (tc && tc->prev) tc = tc->prev;
1321 tc = tc->parent;
1322 }
1323 }
1324