r14292: Janitor for tridge (samba3 talloc is almost identical
[Samba/nascimento.git] / source / lib / talloc.c
blobba189199d71a0faf7196779365375b57c3111024
1 /*
2 Samba Unix SMB/CIFS implementation.
4 Samba trivial allocation library - new interface
6 NOTE: Please read talloc_guide.txt for full documentation
8 Copyright (C) Andrew Tridgell 2004
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
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.
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.
24 You should have received a copy of the GNU Lesser General Public
25 License along with this library; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 inspired by http://swapped.cc/halloc/
33 #ifdef _SAMBA_BUILD_
34 #include "includes.h"
35 #if ((SAMBA_VERSION_MAJOR==3)&&(SAMBA_VERSION_MINOR<9))
36 /* This is to circumvent SAMBA3's paranoid malloc checker. Here in this file
37 * we trust ourselves... */
38 #ifdef malloc
39 #undef malloc
40 #endif
41 #ifdef realloc
42 #undef realloc
43 #endif
44 #endif
45 #else
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <stdarg.h>
50 #include <stdint.h>
51 #include "talloc.h"
52 /* assume a modern system */
53 #define HAVE_VA_COPY
54 #endif
56 /* use this to force every realloc to change the pointer, to stress test
57 code that might not cope */
58 #define ALWAYS_REALLOC 0
61 #define MAX_TALLOC_SIZE 0x10000000
62 #define TALLOC_MAGIC 0xe814ec70
63 #define TALLOC_FLAG_FREE 0x01
64 #define TALLOC_FLAG_LOOP 0x02
65 #define TALLOC_MAGIC_REFERENCE ((const char *)1)
67 /* by default we abort when given a bad pointer (such as when talloc_free() is called
68 on a pointer that came from malloc() */
69 #ifndef TALLOC_ABORT
70 #define TALLOC_ABORT(reason) abort()
71 #endif
73 #ifndef discard_const_p
74 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
75 # define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
76 #else
77 # define discard_const_p(type, ptr) ((type *)(ptr))
78 #endif
79 #endif
81 /* this null_context is only used if talloc_enable_leak_report() or
82 talloc_enable_leak_report_full() is called, otherwise it remains
83 NULL
85 static const void *null_context;
86 static void *cleanup_context;
89 struct talloc_reference_handle {
90 struct talloc_reference_handle *next, *prev;
91 void *ptr;
94 typedef int (*talloc_destructor_t)(void *);
96 struct talloc_chunk {
97 struct talloc_chunk *next, *prev;
98 struct talloc_chunk *parent, *child;
99 struct talloc_reference_handle *refs;
100 talloc_destructor_t destructor;
101 const char *name;
102 size_t size;
103 unsigned flags;
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))
110 /* panic if we get a bad magic value */
111 static struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
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");
118 if (tc->flags & TALLOC_FLAG_FREE) {
119 TALLOC_ABORT("Bad talloc magic value - double free");
121 return tc;
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); \
136 } while (0)
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; \
148 if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
149 } while (0)
153 return the parent chunk of a pointer
155 static struct talloc_chunk *talloc_parent_chunk(const void *ptr)
157 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
158 while (tc->prev) tc=tc->prev;
159 return tc->parent;
162 void *talloc_parent(const void *ptr)
164 struct talloc_chunk *tc = talloc_parent_chunk(ptr);
165 return tc? TC_PTR_FROM_CHUNK(tc) : NULL;
169 Allocate a bit of memory as a child of an existing pointer
171 void *_talloc(const void *context, size_t size)
173 struct talloc_chunk *tc;
175 if (context == NULL) {
176 context = null_context;
179 if (size >= MAX_TALLOC_SIZE) {
180 return NULL;
183 tc = malloc(TC_HDR_SIZE+size);
184 if (tc == NULL) return NULL;
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;
193 if (context) {
194 struct talloc_chunk *parent = talloc_chunk_from_ptr(context);
196 tc->parent = parent;
198 if (parent->child) {
199 parent->child->parent = NULL;
202 _TLIST_ADD(parent->child, tc);
203 } else {
204 tc->next = tc->prev = tc->parent = NULL;
207 return TC_PTR_FROM_CHUNK(tc);
212 setup a destructor to be called on free of a pointer
213 the destructor should return 0 on success, or -1 on failure.
214 if the destructor fails then the free is failed, and the memory can
215 be continued to be used
217 void talloc_set_destructor(const void *ptr, int (*destructor)(void *))
219 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
220 tc->destructor = destructor;
224 increase the reference count on a piece of memory.
226 void talloc_increase_ref_count(const void *ptr)
228 talloc_reference(null_context, ptr);
232 helper for talloc_reference()
234 static int talloc_reference_destructor(void *ptr)
236 struct talloc_reference_handle *handle = ptr;
237 struct talloc_chunk *tc1 = talloc_chunk_from_ptr(ptr);
238 struct talloc_chunk *tc2 = talloc_chunk_from_ptr(handle->ptr);
239 if (tc1->destructor != (talloc_destructor_t)-1) {
240 tc1->destructor = NULL;
242 _TLIST_REMOVE(tc2->refs, handle);
243 talloc_free(handle);
244 return 0;
248 make a secondary reference to a pointer, hanging off the given context.
249 the pointer remains valid until both the original caller and this given
250 context are freed.
252 the major use for this is when two different structures need to reference the
253 same underlying data, and you want to be able to free the two instances separately,
254 and in either order
256 void *talloc_reference(const void *context, const void *ptr)
258 struct talloc_chunk *tc;
259 struct talloc_reference_handle *handle;
260 if (ptr == NULL) return NULL;
262 tc = talloc_chunk_from_ptr(ptr);
263 handle = talloc_named_const(context, sizeof(*handle), TALLOC_MAGIC_REFERENCE);
265 if (handle == NULL) return NULL;
267 /* note that we hang the destructor off the handle, not the
268 main context as that allows the caller to still setup their
269 own destructor on the context if they want to */
270 talloc_set_destructor(handle, talloc_reference_destructor);
271 handle->ptr = discard_const_p(void, ptr);
272 _TLIST_ADD(tc->refs, handle);
273 return handle->ptr;
277 remove a secondary reference to a pointer. This undo's what
278 talloc_reference() has done. The context and pointer arguments
279 must match those given to a talloc_reference()
281 static int talloc_unreference(const void *context, const void *ptr)
283 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
284 struct talloc_reference_handle *h;
286 if (context == NULL) {
287 context = null_context;
290 for (h=tc->refs;h;h=h->next) {
291 struct talloc_chunk *p = talloc_parent_chunk(h);
292 if (p == NULL) {
293 if (context == NULL) break;
294 } else if (TC_PTR_FROM_CHUNK(p) == context) {
295 break;
298 if (h == NULL) {
299 return -1;
302 talloc_set_destructor(h, NULL);
303 _TLIST_REMOVE(tc->refs, h);
304 talloc_free(h);
305 return 0;
309 remove a specific parent context from a pointer. This is a more
310 controlled varient of talloc_free()
312 int talloc_unlink(const void *context, void *ptr)
314 struct talloc_chunk *tc_p, *new_p;
315 void *new_parent;
317 if (ptr == NULL) {
318 return -1;
321 if (context == NULL) {
322 context = null_context;
325 if (talloc_unreference(context, ptr) == 0) {
326 return 0;
329 if (context == NULL) {
330 if (talloc_parent_chunk(ptr) != NULL) {
331 return -1;
333 } else {
334 if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) {
335 return -1;
339 tc_p = talloc_chunk_from_ptr(ptr);
341 if (tc_p->refs == NULL) {
342 return talloc_free(ptr);
345 new_p = talloc_parent_chunk(tc_p->refs);
346 if (new_p) {
347 new_parent = TC_PTR_FROM_CHUNK(new_p);
348 } else {
349 new_parent = NULL;
352 if (talloc_unreference(new_parent, ptr) != 0) {
353 return -1;
356 talloc_steal(new_parent, ptr);
358 return 0;
362 add a name to an existing pointer - va_list version
364 static void talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
366 static void talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
368 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
369 tc->name = talloc_vasprintf(ptr, fmt, ap);
370 if (tc->name) {
371 talloc_set_name_const(tc->name, ".name");
376 add a name to an existing pointer
378 void talloc_set_name(const void *ptr, const char *fmt, ...)
380 va_list ap;
381 va_start(ap, fmt);
382 talloc_set_name_v(ptr, fmt, ap);
383 va_end(ap);
387 more efficient way to add a name to a pointer - the name must point to a
388 true string constant
390 void talloc_set_name_const(const void *ptr, const char *name)
392 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
393 tc->name = name;
397 create a named talloc pointer. Any talloc pointer can be named, and
398 talloc_named() operates just like talloc() except that it allows you
399 to name the pointer.
401 void *talloc_named(const void *context, size_t size, const char *fmt, ...)
403 va_list ap;
404 void *ptr;
406 ptr = _talloc(context, size);
407 if (ptr == NULL) return NULL;
409 va_start(ap, fmt);
410 talloc_set_name_v(ptr, fmt, ap);
411 va_end(ap);
413 return ptr;
417 create a named talloc pointer. Any talloc pointer can be named, and
418 talloc_named() operates just like talloc() except that it allows you
419 to name the pointer.
421 void *talloc_named_const(const void *context, size_t size, const char *name)
423 void *ptr;
425 ptr = _talloc(context, size);
426 if (ptr == NULL) {
427 return NULL;
430 talloc_set_name_const(ptr, name);
432 return ptr;
436 return the name of a talloc ptr, or "UNNAMED"
438 const char *talloc_get_name(const void *ptr)
440 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
441 if (tc->name == TALLOC_MAGIC_REFERENCE) {
442 return ".reference";
444 if (tc->name) {
445 return tc->name;
447 return "UNNAMED";
452 check if a pointer has the given name. If it does, return the pointer,
453 otherwise return NULL
455 void *talloc_check_name(const void *ptr, const char *name)
457 const char *pname;
458 if (ptr == NULL) return NULL;
459 pname = talloc_get_name(ptr);
460 if (pname == name || strcmp(pname, name) == 0) {
461 return discard_const_p(void, ptr);
463 return NULL;
468 this is for compatibility with older versions of talloc
470 void *talloc_init(const char *fmt, ...)
472 va_list ap;
473 void *ptr;
475 talloc_enable_null_tracking();
477 ptr = _talloc(NULL, 0);
478 if (ptr == NULL) return NULL;
480 va_start(ap, fmt);
481 talloc_set_name_v(ptr, fmt, ap);
482 va_end(ap);
484 return ptr;
488 this is a replacement for the Samba3 talloc_destroy_pool functionality. It
489 should probably not be used in new code. It's in here to keep the talloc
490 code consistent across Samba 3 and 4.
492 void talloc_free_children(void *ptr)
494 struct talloc_chunk *tc;
496 if (ptr == NULL) {
497 return;
500 tc = talloc_chunk_from_ptr(ptr);
502 while (tc->child) {
503 /* we need to work out who will own an abandoned child
504 if it cannot be freed. In priority order, the first
505 choice is owner of any remaining reference to this
506 pointer, the second choice is our parent, and the
507 final choice is the null context. */
508 void *child = TC_PTR_FROM_CHUNK(tc->child);
509 const void *new_parent = null_context;
510 if (tc->child->refs) {
511 struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
512 if (p) new_parent = TC_PTR_FROM_CHUNK(p);
514 if (talloc_free(child) == -1) {
515 if (new_parent == null_context) {
516 struct talloc_chunk *p = talloc_parent_chunk(ptr);
517 if (p) new_parent = TC_PTR_FROM_CHUNK(p);
519 talloc_steal(new_parent, child);
525 free a talloc pointer. This also frees all child pointers of this
526 pointer recursively
528 return 0 if the memory is actually freed, otherwise -1. The memory
529 will not be freed if the ref_count is > 1 or the destructor (if
530 any) returns non-zero
532 int talloc_free(void *ptr)
534 struct talloc_chunk *tc;
536 if (ptr == NULL) {
537 return -1;
540 tc = talloc_chunk_from_ptr(ptr);
542 if (tc->refs) {
543 talloc_reference_destructor(tc->refs);
544 return -1;
547 if (tc->flags & TALLOC_FLAG_LOOP) {
548 /* we have a free loop - stop looping */
549 return 0;
552 if (tc->destructor) {
553 talloc_destructor_t d = tc->destructor;
554 if (d == (talloc_destructor_t)-1) {
555 return -1;
557 tc->destructor = (talloc_destructor_t)-1;
558 if (d(ptr) == -1) {
559 tc->destructor = d;
560 return -1;
562 tc->destructor = NULL;
565 tc->flags |= TALLOC_FLAG_LOOP;
567 talloc_free_children(ptr);
569 if (tc->parent) {
570 _TLIST_REMOVE(tc->parent->child, tc);
571 if (tc->parent->child) {
572 tc->parent->child->parent = tc->parent;
574 } else {
575 if (tc->prev) tc->prev->next = tc->next;
576 if (tc->next) tc->next->prev = tc->prev;
579 tc->flags |= TALLOC_FLAG_FREE;
581 free(tc);
582 return 0;
588 A talloc version of realloc. The context argument is only used if
589 ptr is NULL
591 void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name)
593 struct talloc_chunk *tc;
594 void *new_ptr;
596 /* size zero is equivalent to free() */
597 if (size == 0) {
598 talloc_free(ptr);
599 return NULL;
602 if (size >= MAX_TALLOC_SIZE) {
603 return NULL;
606 /* realloc(NULL) is equavalent to malloc() */
607 if (ptr == NULL) {
608 return talloc_named_const(context, size, name);
611 tc = talloc_chunk_from_ptr(ptr);
613 /* don't allow realloc on referenced pointers */
614 if (tc->refs) {
615 return NULL;
618 /* by resetting magic we catch users of the old memory */
619 tc->flags |= TALLOC_FLAG_FREE;
621 #if ALWAYS_REALLOC
622 new_ptr = malloc(size + TC_HDR_SIZE);
623 if (new_ptr) {
624 memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE);
625 free(tc);
627 #else
628 new_ptr = realloc(tc, size + TC_HDR_SIZE);
629 #endif
630 if (!new_ptr) {
631 tc->flags &= ~TALLOC_FLAG_FREE;
632 return NULL;
635 tc = new_ptr;
636 tc->flags &= ~TALLOC_FLAG_FREE;
637 if (tc->parent) {
638 tc->parent->child = new_ptr;
640 if (tc->child) {
641 tc->child->parent = new_ptr;
644 if (tc->prev) {
645 tc->prev->next = tc;
647 if (tc->next) {
648 tc->next->prev = tc;
651 tc->size = size;
652 talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
654 return TC_PTR_FROM_CHUNK(tc);
658 move a lump of memory from one talloc context to another return the
659 ptr on success, or NULL if it could not be transferred.
660 passing NULL as ptr will always return NULL with no side effects.
662 void *talloc_steal(const void *new_ctx, const void *ptr)
664 struct talloc_chunk *tc, *new_tc;
666 if (!ptr) {
667 return NULL;
670 if (new_ctx == NULL) {
671 new_ctx = null_context;
674 tc = talloc_chunk_from_ptr(ptr);
676 if (new_ctx == NULL) {
677 if (tc->parent) {
678 _TLIST_REMOVE(tc->parent->child, tc);
679 if (tc->parent->child) {
680 tc->parent->child->parent = tc->parent;
682 } else {
683 if (tc->prev) tc->prev->next = tc->next;
684 if (tc->next) tc->next->prev = tc->prev;
687 tc->parent = tc->next = tc->prev = NULL;
688 return discard_const_p(void, ptr);
691 new_tc = talloc_chunk_from_ptr(new_ctx);
693 if (tc == new_tc) {
694 return discard_const_p(void, ptr);
697 if (tc->parent) {
698 _TLIST_REMOVE(tc->parent->child, tc);
699 if (tc->parent->child) {
700 tc->parent->child->parent = tc->parent;
702 } else {
703 if (tc->prev) tc->prev->next = tc->next;
704 if (tc->next) tc->next->prev = tc->prev;
707 tc->parent = new_tc;
708 if (new_tc->child) new_tc->child->parent = NULL;
709 _TLIST_ADD(new_tc->child, tc);
711 return discard_const_p(void, ptr);
715 return the total size of a talloc pool (subtree)
717 off_t talloc_total_size(const void *ptr)
719 off_t total = 0;
720 struct talloc_chunk *c, *tc;
722 if (ptr == NULL) {
723 ptr = null_context;
725 if (ptr == NULL) {
726 return 0;
729 tc = talloc_chunk_from_ptr(ptr);
731 if (tc->flags & TALLOC_FLAG_LOOP) {
732 return 0;
735 tc->flags |= TALLOC_FLAG_LOOP;
737 total = tc->size;
738 for (c=tc->child;c;c=c->next) {
739 total += talloc_total_size(TC_PTR_FROM_CHUNK(c));
742 tc->flags &= ~TALLOC_FLAG_LOOP;
744 return total;
748 return the total number of blocks in a talloc pool (subtree)
750 off_t talloc_total_blocks(const void *ptr)
752 off_t total = 0;
753 struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
755 if (tc->flags & TALLOC_FLAG_LOOP) {
756 return 0;
759 tc->flags |= TALLOC_FLAG_LOOP;
761 total++;
762 for (c=tc->child;c;c=c->next) {
763 total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c));
766 tc->flags &= ~TALLOC_FLAG_LOOP;
768 return total;
772 return the number of external references to a pointer
774 static int talloc_reference_count(const void *ptr)
776 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
777 struct talloc_reference_handle *h;
778 int ret = 0;
780 for (h=tc->refs;h;h=h->next) {
781 ret++;
783 return ret;
787 report on memory usage by all children of a pointer, giving a full tree view
789 void talloc_report_depth(const void *ptr, FILE *f, int depth)
791 struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
793 if (tc->flags & TALLOC_FLAG_LOOP) {
794 return;
797 tc->flags |= TALLOC_FLAG_LOOP;
799 for (c=tc->child;c;c=c->next) {
800 if (c->name == TALLOC_MAGIC_REFERENCE) {
801 struct talloc_reference_handle *handle = TC_PTR_FROM_CHUNK(c);
802 const char *name2 = talloc_get_name(handle->ptr);
803 fprintf(f, "%*sreference to: %s\n", depth*4, "", name2);
804 } else {
805 const char *name = talloc_get_name(TC_PTR_FROM_CHUNK(c));
806 fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n",
807 depth*4, "",
808 name,
809 (unsigned long)talloc_total_size(TC_PTR_FROM_CHUNK(c)),
810 (unsigned long)talloc_total_blocks(TC_PTR_FROM_CHUNK(c)),
811 talloc_reference_count(TC_PTR_FROM_CHUNK(c)));
812 talloc_report_depth(TC_PTR_FROM_CHUNK(c), f, depth+1);
815 tc->flags &= ~TALLOC_FLAG_LOOP;
819 report on memory usage by all children of a pointer, giving a full tree view
821 void talloc_report_full(const void *ptr, FILE *f)
823 if (ptr == NULL) {
824 ptr = null_context;
826 if (ptr == NULL) return;
828 fprintf(f,"full talloc report on '%s' (total %lu bytes in %lu blocks)\n",
829 talloc_get_name(ptr),
830 (unsigned long)talloc_total_size(ptr),
831 (unsigned long)talloc_total_blocks(ptr));
833 talloc_report_depth(ptr, f, 1);
834 fflush(f);
838 report on memory usage by all children of a pointer
840 void talloc_report(const void *ptr, FILE *f)
842 struct talloc_chunk *c, *tc;
844 if (ptr == NULL) {
845 ptr = null_context;
847 if (ptr == NULL) return;
849 fprintf(f,"talloc report on '%s' (total %lu bytes in %lu blocks)\n",
850 talloc_get_name(ptr),
851 (unsigned long)talloc_total_size(ptr),
852 (unsigned long)talloc_total_blocks(ptr));
854 tc = talloc_chunk_from_ptr(ptr);
856 for (c=tc->child;c;c=c->next) {
857 fprintf(f, "\t%-30s contains %6lu bytes in %3lu blocks\n",
858 talloc_get_name(TC_PTR_FROM_CHUNK(c)),
859 (unsigned long)talloc_total_size(TC_PTR_FROM_CHUNK(c)),
860 (unsigned long)talloc_total_blocks(TC_PTR_FROM_CHUNK(c)));
862 fflush(f);
866 report on any memory hanging off the null context
868 static void talloc_report_null(void)
870 if (talloc_total_size(null_context) != 0) {
871 talloc_report(null_context, stderr);
876 report on any memory hanging off the null context
878 static void talloc_report_null_full(void)
880 if (talloc_total_size(null_context) != 0) {
881 talloc_report_full(null_context, stderr);
886 enable tracking of the NULL context
888 void talloc_enable_null_tracking(void)
890 if (null_context == NULL) {
891 null_context = talloc_named_const(NULL, 0, "null_context");
895 #ifdef _SAMBA_BUILD_
896 /* Ugly calls to Samba-specific sprintf_append... JRA. */
899 report on memory usage by all children of a pointer, giving a full tree view
901 static void talloc_report_depth_str(const void *ptr, char **pps, ssize_t *plen, size_t *pbuflen, int depth)
903 struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
905 if (tc->flags & TALLOC_FLAG_LOOP) {
906 return;
909 tc->flags |= TALLOC_FLAG_LOOP;
911 for (c=tc->child;c;c=c->next) {
912 if (c->name == TALLOC_MAGIC_REFERENCE) {
913 struct talloc_reference_handle *handle = TC_PTR_FROM_CHUNK(c);
914 const char *name2 = talloc_get_name(handle->ptr);
916 sprintf_append(NULL, pps, plen, pbuflen,
917 "%*sreference to: %s\n", depth*4, "", name2);
919 } else {
920 const char *name = talloc_get_name(TC_PTR_FROM_CHUNK(c));
922 sprintf_append(NULL, pps, plen, pbuflen,
923 "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n",
924 depth*4, "",
925 name,
926 (unsigned long)talloc_total_size(TC_PTR_FROM_CHUNK(c)),
927 (unsigned long)talloc_total_blocks(TC_PTR_FROM_CHUNK(c)),
928 talloc_reference_count(TC_PTR_FROM_CHUNK(c)));
930 talloc_report_depth_str(TC_PTR_FROM_CHUNK(c), pps, plen, pbuflen, depth+1);
933 tc->flags &= ~TALLOC_FLAG_LOOP;
937 report on memory usage by all children of a pointer
939 char *talloc_describe_all(void)
941 ssize_t len = 0;
942 size_t buflen = 512;
943 char *s = NULL;
945 if (null_context == NULL) {
946 return NULL;
949 sprintf_append(NULL, &s, &len, &buflen,
950 "full talloc report on '%s' (total %lu bytes in %lu blocks)\n",
951 talloc_get_name(null_context),
952 (unsigned long)talloc_total_size(null_context),
953 (unsigned long)talloc_total_blocks(null_context));
955 if (!s) {
956 return NULL;
958 talloc_report_depth_str(null_context, &s, &len, &buflen, 1);
959 return s;
961 #endif
964 enable leak reporting on exit
966 void talloc_enable_leak_report(void)
968 talloc_enable_null_tracking();
969 atexit(talloc_report_null);
973 enable full leak reporting on exit
975 void talloc_enable_leak_report_full(void)
977 talloc_enable_null_tracking();
978 atexit(talloc_report_null_full);
982 talloc and zero memory.
984 void *_talloc_zero(const void *ctx, size_t size, const char *name)
986 void *p = talloc_named_const(ctx, size, name);
988 if (p) {
989 memset(p, '\0', size);
992 return p;
997 memdup with a talloc.
999 void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name)
1001 void *newp = talloc_named_const(t, size, name);
1003 if (newp) {
1004 memcpy(newp, p, size);
1007 return newp;
1011 strdup with a talloc
1013 char *talloc_strdup(const void *t, const char *p)
1015 char *ret;
1016 if (!p) {
1017 return NULL;
1019 ret = talloc_memdup(t, p, strlen(p) + 1);
1020 if (ret) {
1021 talloc_set_name_const(ret, ret);
1023 return ret;
1027 append to a talloced string
1029 char *talloc_append_string(const void *t, char *orig, const char *append)
1031 char *ret;
1032 size_t olen = strlen(orig);
1033 size_t alenz;
1035 if (!append)
1036 return orig;
1038 alenz = strlen(append) + 1;
1040 ret = talloc_realloc(t, orig, char, olen + alenz);
1041 if (!ret)
1042 return NULL;
1044 /* append the string with the trailing \0 */
1045 memcpy(&ret[olen], append, alenz);
1047 return ret;
1051 strndup with a talloc
1053 char *talloc_strndup(const void *t, const char *p, size_t n)
1055 size_t len;
1056 char *ret;
1058 for (len=0; len<n && p[len]; len++) ;
1060 ret = _talloc(t, len + 1);
1061 if (!ret) { return NULL; }
1062 memcpy(ret, p, len);
1063 ret[len] = 0;
1064 talloc_set_name_const(ret, ret);
1065 return ret;
1068 #ifndef VA_COPY
1069 #ifdef HAVE_VA_COPY
1070 #define VA_COPY(dest, src) va_copy(dest, src)
1071 #elif defined(HAVE___VA_COPY)
1072 #define VA_COPY(dest, src) __va_copy(dest, src)
1073 #else
1074 #define VA_COPY(dest, src) (dest) = (src)
1075 #endif
1076 #endif
1078 char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
1080 int len;
1081 char *ret;
1082 va_list ap2;
1083 char c;
1085 VA_COPY(ap2, ap);
1087 /* this call looks strange, but it makes it work on older solaris boxes */
1088 if ((len = vsnprintf(&c, 1, fmt, ap2)) < 0) {
1089 return NULL;
1092 ret = _talloc(t, len+1);
1093 if (ret) {
1094 VA_COPY(ap2, ap);
1095 vsnprintf(ret, len+1, fmt, ap2);
1096 talloc_set_name_const(ret, ret);
1099 return ret;
1104 Perform string formatting, and return a pointer to newly allocated
1105 memory holding the result, inside a memory pool.
1107 char *talloc_asprintf(const void *t, const char *fmt, ...)
1109 va_list ap;
1110 char *ret;
1112 va_start(ap, fmt);
1113 ret = talloc_vasprintf(t, fmt, ap);
1114 va_end(ap);
1115 return ret;
1120 * Realloc @p s to append the formatted result of @p fmt and @p ap,
1121 * and return @p s, which may have moved. Good for gradually
1122 * accumulating output into a string buffer.
1125 static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
1127 static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
1129 struct talloc_chunk *tc;
1130 int len, s_len;
1131 va_list ap2;
1133 if (s == NULL) {
1134 return talloc_vasprintf(NULL, fmt, ap);
1137 tc = talloc_chunk_from_ptr(s);
1139 VA_COPY(ap2, ap);
1141 s_len = tc->size - 1;
1142 if ((len = vsnprintf(NULL, 0, fmt, ap2)) <= 0) {
1143 /* Either the vsnprintf failed or the format resulted in
1144 * no characters being formatted. In the former case, we
1145 * ought to return NULL, in the latter we ought to return
1146 * the original string. Most current callers of this
1147 * function expect it to never return NULL.
1149 return s;
1152 s = talloc_realloc(NULL, s, char, s_len + len+1);
1153 if (!s) return NULL;
1155 VA_COPY(ap2, ap);
1157 vsnprintf(s+s_len, len+1, fmt, ap2);
1158 talloc_set_name_const(s, s);
1160 return s;
1164 Realloc @p s to append the formatted result of @p fmt and return @p
1165 s, which may have moved. Good for gradually accumulating output
1166 into a string buffer.
1168 char *talloc_asprintf_append(char *s, const char *fmt, ...)
1170 va_list ap;
1172 va_start(ap, fmt);
1173 s = talloc_vasprintf_append(s, fmt, ap);
1174 va_end(ap);
1175 return s;
1179 alloc an array, checking for integer overflow in the array size
1181 void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
1183 if (count >= MAX_TALLOC_SIZE/el_size) {
1184 return NULL;
1186 return talloc_named_const(ctx, el_size * count, name);
1190 alloc an zero array, checking for integer overflow in the array size
1192 void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name)
1194 if (count >= MAX_TALLOC_SIZE/el_size) {
1195 return NULL;
1197 return _talloc_zero(ctx, el_size * count, name);
1202 realloc an array, checking for integer overflow in the array size
1204 void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
1206 if (count >= MAX_TALLOC_SIZE/el_size) {
1207 return NULL;
1209 return _talloc_realloc(ctx, ptr, el_size * count, name);
1213 a function version of talloc_realloc(), so it can be passed as a function pointer
1214 to libraries that want a realloc function (a realloc function encapsulates
1215 all the basic capabilities of an allocation library, which is why this is useful)
1217 void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
1219 return _talloc_realloc(context, ptr, size, NULL);
1223 static void talloc_autofree(void)
1225 talloc_free(cleanup_context);
1226 cleanup_context = NULL;
1230 return a context which will be auto-freed on exit
1231 this is useful for reducing the noise in leak reports
1233 void *talloc_autofree_context(void)
1235 if (cleanup_context == NULL) {
1236 cleanup_context = talloc_named_const(NULL, 0, "autofree_context");
1237 atexit(talloc_autofree);
1239 return cleanup_context;
1242 size_t talloc_get_size(const void *context)
1244 struct talloc_chunk *tc;
1246 if (context == NULL)
1247 return 0;
1249 tc = talloc_chunk_from_ptr(context);
1251 return tc->size;
1255 find a parent of this context that has the given name, if any
1257 void *talloc_find_parent_byname(const void *context, const char *name)
1259 struct talloc_chunk *tc;
1261 if (context == NULL) {
1262 return NULL;
1265 tc = talloc_chunk_from_ptr(context);
1266 while (tc) {
1267 if (tc->name && strcmp(tc->name, name) == 0) {
1268 return TC_PTR_FROM_CHUNK(tc);
1270 while (tc && tc->prev) tc = tc->prev;
1271 tc = tc->parent;
1273 return NULL;
1277 show the parentage of a context
1279 void talloc_show_parents(const void *context, FILE *file)
1281 struct talloc_chunk *tc;
1283 if (context == NULL) {
1284 fprintf(file, "talloc no parents for NULL\n");
1285 return;
1288 tc = talloc_chunk_from_ptr(context);
1289 fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
1290 while (tc) {
1291 fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)));
1292 while (tc && tc->prev) tc = tc->prev;
1293 tc = tc->parent;