Initial import
[samba] / source / lib / talloc.c
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, write to the Free Software
26    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27 */
28
29 /*
30   inspired by http://swapped.cc/halloc/
31 */
32
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
55
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
59
60
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)
66
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
72
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
80
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
84 */
85 static const void *null_context;
86 static void *cleanup_context;
87
88
89 struct talloc_reference_handle {
90         struct talloc_reference_handle *next, *prev;
91         void *ptr;
92 };
93
94 typedef int (*talloc_destructor_t)(void *);
95
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;
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 */
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 */
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
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 */
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
193         if (context) {
194                 struct talloc_chunk *parent = talloc_chunk_from_ptr(context);
195
196                 tc->parent = parent;
197
198                 if (parent->child) {
199                         parent->child->parent = NULL;
200                 }
201
202                 _TLIST_ADD(parent->child, tc);
203         } else {
204                 tc->next = tc->prev = tc->parent = NULL;
205         }
206
207         return TC_PTR_FROM_CHUNK(tc);
208 }
209
210
211 /*
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
216 */
217 void talloc_set_destructor(const void *ptr, int (*destructor)(void *))
218 {
219         struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
220         tc->destructor = destructor;
221 }
222
223 /*
224   increase the reference count on a piece of memory. 
225 */
226 void talloc_increase_ref_count(const void *ptr)
227 {
228         talloc_reference(null_context, ptr);
229 }
230
231 /*
232   helper for talloc_reference()
233 */
234 static int talloc_reference_destructor(void *ptr)
235 {
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;
241         }
242         _TLIST_REMOVE(tc2->refs, handle);
243         talloc_free(handle);
244         return 0;
245 }
246
247 /*
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.
251   
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
255 */
256 void *talloc_reference(const void *context, const void *ptr)
257 {
258         struct talloc_chunk *tc;
259         struct talloc_reference_handle *handle;
260         if (ptr == NULL) return NULL;
261
262         tc = talloc_chunk_from_ptr(ptr);
263         handle = talloc_named_const(context, sizeof(*handle), TALLOC_MAGIC_REFERENCE);
264
265         if (handle == NULL) return NULL;
266
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;
274 }
275
276 /*
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()
280 */
281 static int talloc_unreference(const void *context, const void *ptr)
282 {
283         struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
284         struct talloc_reference_handle *h;
285
286         if (context == NULL) {
287                 context = null_context;
288         }
289
290         for (h=tc->refs;h;h=h->next) {
291                 struct talloc_chunk *p = talloc_parent_chunk(h);
292                 if ((p==NULL && context==NULL) || TC_PTR_FROM_CHUNK(p) == context) break;
293         }
294         if (h == NULL) {
295                 return -1;
296         }
297
298         talloc_set_destructor(h, NULL);
299         _TLIST_REMOVE(tc->refs, h);
300         talloc_free(h);
301         return 0;
302 }
303
304 /*
305   remove a specific parent context from a pointer. This is a more
306   controlled varient of talloc_free()
307 */
308 int talloc_unlink(const void *context, void *ptr)
309 {
310         struct talloc_chunk *tc_p, *new_p;
311         void *new_parent;
312
313         if (ptr == NULL) {
314                 return -1;
315         }
316
317         if (context == NULL) {
318                 context = null_context;
319         }
320
321         if (talloc_unreference(context, ptr) == 0) {
322                 return 0;
323         }
324
325         if (context == NULL) {
326                 if (talloc_parent_chunk(ptr) != NULL) {
327                         return -1;
328                 }
329         } else {
330                 if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) {
331                         return -1;
332                 }
333         }
334         
335         tc_p = talloc_chunk_from_ptr(ptr);
336
337         if (tc_p->refs == NULL) {
338                 return talloc_free(ptr);
339         }
340
341         new_p = talloc_parent_chunk(tc_p->refs);
342         if (new_p) {
343                 new_parent = TC_PTR_FROM_CHUNK(new_p);
344         } else {
345                 new_parent = NULL;
346         }
347
348         if (talloc_unreference(new_parent, ptr) != 0) {
349                 return -1;
350         }
351
352         talloc_steal(new_parent, ptr);
353
354         return 0;
355 }
356
357 /*
358   add a name to an existing pointer - va_list version
359 */
360 static void talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
361
362 static void talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
363 {
364         struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
365         tc->name = talloc_vasprintf(ptr, fmt, ap);
366         if (tc->name) {
367                 talloc_set_name_const(tc->name, ".name");
368         }
369 }
370
371 /*
372   add a name to an existing pointer
373 */
374 void talloc_set_name(const void *ptr, const char *fmt, ...)
375 {
376         va_list ap;
377         va_start(ap, fmt);
378         talloc_set_name_v(ptr, fmt, ap);
379         va_end(ap);
380 }
381
382 /*
383    more efficient way to add a name to a pointer - the name must point to a 
384    true string constant
385 */
386 void talloc_set_name_const(const void *ptr, const char *name)
387 {
388         struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
389         tc->name = name;
390 }
391
392 /*
393   create a named talloc pointer. Any talloc pointer can be named, and
394   talloc_named() operates just like talloc() except that it allows you
395   to name the pointer.
396 */
397 void *talloc_named(const void *context, size_t size, const char *fmt, ...)
398 {
399         va_list ap;
400         void *ptr;
401
402         ptr = _talloc(context, size);
403         if (ptr == NULL) return NULL;
404
405         va_start(ap, fmt);
406         talloc_set_name_v(ptr, fmt, ap);
407         va_end(ap);
408
409         return ptr;
410 }
411
412 /*
413   create a named talloc pointer. Any talloc pointer can be named, and
414   talloc_named() operates just like talloc() except that it allows you
415   to name the pointer.
416 */
417 void *talloc_named_const(const void *context, size_t size, const char *name)
418 {
419         void *ptr;
420
421         ptr = _talloc(context, size);
422         if (ptr == NULL) {
423                 return NULL;
424         }
425
426         talloc_set_name_const(ptr, name);
427
428         return ptr;
429 }
430
431 /*
432   return the name of a talloc ptr, or "UNNAMED"
433 */
434 const char *talloc_get_name(const void *ptr)
435 {
436         struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
437         if (tc->name == TALLOC_MAGIC_REFERENCE) {
438                 return ".reference";
439         }
440         if (tc->name) {
441                 return tc->name;
442         }
443         return "UNNAMED";
444 }
445
446
447 /*
448   check if a pointer has the given name. If it does, return the pointer,
449   otherwise return NULL
450 */
451 void *talloc_check_name(const void *ptr, const char *name)
452 {
453         const char *pname;
454         if (ptr == NULL) return NULL;
455         pname = talloc_get_name(ptr);
456         if (pname == name || strcmp(pname, name) == 0) {
457                 return discard_const_p(void, ptr);
458         }
459         return NULL;
460 }
461
462
463 /*
464   this is for compatibility with older versions of talloc
465 */
466 void *talloc_init(const char *fmt, ...)
467 {
468         va_list ap;
469         void *ptr;
470
471         talloc_enable_null_tracking();
472
473         ptr = _talloc(NULL, 0);
474         if (ptr == NULL) return NULL;
475
476         va_start(ap, fmt);
477         talloc_set_name_v(ptr, fmt, ap);
478         va_end(ap);
479
480         return ptr;
481 }
482
483 /*
484   this is a replacement for the Samba3 talloc_destroy_pool functionality. It
485   should probably not be used in new code. It's in here to keep the talloc
486   code consistent across Samba 3 and 4.
487 */
488 void talloc_free_children(void *ptr)
489 {
490         struct talloc_chunk *tc;
491
492         if (ptr == NULL) {
493                 return;
494         }
495
496         tc = talloc_chunk_from_ptr(ptr);
497
498         while (tc->child) {
499                 /* we need to work out who will own an abandoned child
500                    if it cannot be freed. In priority order, the first
501                    choice is owner of any remaining reference to this
502                    pointer, the second choice is our parent, and the
503                    final choice is the null context. */
504                 void *child = TC_PTR_FROM_CHUNK(tc->child);
505                 const void *new_parent = null_context;
506                 if (tc->child->refs) {
507                         struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
508                         if (p) new_parent = TC_PTR_FROM_CHUNK(p);
509                 }
510                 if (talloc_free(child) == -1) {
511                         if (new_parent == null_context) {
512                                 struct talloc_chunk *p = talloc_parent_chunk(ptr);
513                                 if (p) new_parent = TC_PTR_FROM_CHUNK(p);
514                         }
515                         talloc_steal(new_parent, child);
516                 }
517         }
518 }
519
520 /* 
521    free a talloc pointer. This also frees all child pointers of this 
522    pointer recursively
523
524    return 0 if the memory is actually freed, otherwise -1. The memory
525    will not be freed if the ref_count is > 1 or the destructor (if
526    any) returns non-zero
527 */
528 int talloc_free(void *ptr)
529 {
530         struct talloc_chunk *tc;
531
532         if (ptr == NULL) {
533                 return -1;
534         }
535
536         tc = talloc_chunk_from_ptr(ptr);
537
538         if (tc->refs) {
539                 talloc_reference_destructor(tc->refs);
540                 return -1;
541         }
542
543         if (tc->flags & TALLOC_FLAG_LOOP) {
544                 /* we have a free loop - stop looping */
545                 return 0;
546         }
547
548         if (tc->destructor) {
549                 talloc_destructor_t d = tc->destructor;
550                 if (d == (talloc_destructor_t)-1) {
551                         return -1;
552                 }
553                 tc->destructor = (talloc_destructor_t)-1;
554                 if (d(ptr) == -1) {
555                         tc->destructor = d;
556                         return -1;
557                 }
558                 tc->destructor = NULL;
559         }
560
561         tc->flags |= TALLOC_FLAG_LOOP;
562
563         talloc_free_children(ptr);
564
565         if (tc->parent) {
566                 _TLIST_REMOVE(tc->parent->child, tc);
567                 if (tc->parent->child) {
568                         tc->parent->child->parent = tc->parent;
569                 }
570         } else {
571                 if (tc->prev) tc->prev->next = tc->next;
572                 if (tc->next) tc->next->prev = tc->prev;
573         }
574
575         tc->flags |= TALLOC_FLAG_FREE;
576
577         free(tc);
578         return 0;
579 }
580
581
582
583 /*
584   A talloc version of realloc. The context argument is only used if
585   ptr is NULL
586 */
587 void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name)
588 {
589         struct talloc_chunk *tc;
590         void *new_ptr;
591
592         /* size zero is equivalent to free() */
593         if (size == 0) {
594                 talloc_free(ptr);
595                 return NULL;
596         }
597
598         if (size >= MAX_TALLOC_SIZE) {
599                 return NULL;
600         }
601
602         /* realloc(NULL) is equavalent to malloc() */
603         if (ptr == NULL) {
604                 return talloc_named_const(context, size, name);
605         }
606
607         tc = talloc_chunk_from_ptr(ptr);
608
609         /* don't allow realloc on referenced pointers */
610         if (tc->refs) {
611                 return NULL;
612         }
613
614         /* by resetting magic we catch users of the old memory */
615         tc->flags |= TALLOC_FLAG_FREE;
616
617 #if ALWAYS_REALLOC
618         new_ptr = malloc(size + TC_HDR_SIZE);
619         if (new_ptr) {
620                 memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE);
621                 free(tc);
622         }
623 #else
624         new_ptr = realloc(tc, size + TC_HDR_SIZE);
625 #endif
626         if (!new_ptr) { 
627                 tc->flags &= ~TALLOC_FLAG_FREE; 
628                 return NULL; 
629         }
630
631         tc = new_ptr;
632         tc->flags &= ~TALLOC_FLAG_FREE; 
633         if (tc->parent) {
634                 tc->parent->child = new_ptr;
635         }
636         if (tc->child) {
637                 tc->child->parent = new_ptr;
638         }
639
640         if (tc->prev) {
641                 tc->prev->next = tc;
642         }
643         if (tc->next) {
644                 tc->next->prev = tc;
645         }
646
647         tc->size = size;
648         talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
649
650         return TC_PTR_FROM_CHUNK(tc);
651 }
652
653 /* 
654    move a lump of memory from one talloc context to another return the
655    ptr on success, or NULL if it could not be transferred.
656    passing NULL as ptr will always return NULL with no side effects.
657 */
658 void *talloc_steal(const void *new_ctx, const void *ptr)
659 {
660         struct talloc_chunk *tc, *new_tc;
661
662         if (!ptr) {
663                 return NULL;
664         }
665
666         if (new_ctx == NULL) {
667                 new_ctx = null_context;
668         }
669
670         tc = talloc_chunk_from_ptr(ptr);
671
672         if (new_ctx == NULL) {
673                 if (tc->parent) {
674                         _TLIST_REMOVE(tc->parent->child, tc);
675                         if (tc->parent->child) {
676                                 tc->parent->child->parent = tc->parent;
677                         }
678                 } else {
679                         if (tc->prev) tc->prev->next = tc->next;
680                         if (tc->next) tc->next->prev = tc->prev;
681                 }
682                 
683                 tc->parent = tc->next = tc->prev = NULL;
684                 return discard_const_p(void, ptr);
685         }
686
687         new_tc = talloc_chunk_from_ptr(new_ctx);
688
689         if (tc == new_tc) {
690                 return discard_const_p(void, ptr);
691         }
692
693         if (tc->parent) {
694                 _TLIST_REMOVE(tc->parent->child, tc);
695                 if (tc->parent->child) {
696                         tc->parent->child->parent = tc->parent;
697                 }
698         } else {
699                 if (tc->prev) tc->prev->next = tc->next;
700                 if (tc->next) tc->next->prev = tc->prev;
701         }
702
703         tc->parent = new_tc;
704         if (new_tc->child) new_tc->child->parent = NULL;
705         _TLIST_ADD(new_tc->child, tc);
706
707         return discard_const_p(void, ptr);
708 }
709
710 /*
711   return the total size of a talloc pool (subtree)
712 */
713 off_t talloc_total_size(const void *ptr)
714 {
715         off_t total = 0;
716         struct talloc_chunk *c, *tc;
717         
718         if (ptr == NULL) {
719                 ptr = null_context;
720         }
721         if (ptr == NULL) {
722                 return 0;
723         }
724
725         tc = talloc_chunk_from_ptr(ptr);
726
727         if (tc->flags & TALLOC_FLAG_LOOP) {
728                 return 0;
729         }
730
731         tc->flags |= TALLOC_FLAG_LOOP;
732
733         total = tc->size;
734         for (c=tc->child;c;c=c->next) {
735                 total += talloc_total_size(TC_PTR_FROM_CHUNK(c));
736         }
737
738         tc->flags &= ~TALLOC_FLAG_LOOP;
739
740         return total;
741 }
742
743 /*
744   return the total number of blocks in a talloc pool (subtree)
745 */
746 off_t talloc_total_blocks(const void *ptr)
747 {
748         off_t total = 0;
749         struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
750
751         if (tc->flags & TALLOC_FLAG_LOOP) {
752                 return 0;
753         }
754
755         tc->flags |= TALLOC_FLAG_LOOP;
756
757         total++;
758         for (c=tc->child;c;c=c->next) {
759                 total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c));
760         }
761
762         tc->flags &= ~TALLOC_FLAG_LOOP;
763
764         return total;
765 }
766
767 /*
768   return the number of external references to a pointer
769 */
770 static int talloc_reference_count(const void *ptr)
771 {
772         struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
773         struct talloc_reference_handle *h;
774         int ret = 0;
775
776         for (h=tc->refs;h;h=h->next) {
777                 ret++;
778         }
779         return ret;
780 }
781
782 /*
783   report on memory usage by all children of a pointer, giving a full tree view
784 */
785 void talloc_report_depth(const void *ptr, FILE *f, int depth)
786 {
787         struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
788
789         if (tc->flags & TALLOC_FLAG_LOOP) {
790                 return;
791         }
792
793         tc->flags |= TALLOC_FLAG_LOOP;
794
795         for (c=tc->child;c;c=c->next) {
796                 if (c->name == TALLOC_MAGIC_REFERENCE) {
797                         struct talloc_reference_handle *handle = TC_PTR_FROM_CHUNK(c);
798                         const char *name2 = talloc_get_name(handle->ptr);
799                         fprintf(f, "%*sreference to: %s\n", depth*4, "", name2);
800                 } else {
801                         const char *name = talloc_get_name(TC_PTR_FROM_CHUNK(c));
802                         fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n", 
803                                 depth*4, "",
804                                 name,
805                                 (unsigned long)talloc_total_size(TC_PTR_FROM_CHUNK(c)),
806                                 (unsigned long)talloc_total_blocks(TC_PTR_FROM_CHUNK(c)),
807                                 talloc_reference_count(TC_PTR_FROM_CHUNK(c)));
808                         talloc_report_depth(TC_PTR_FROM_CHUNK(c), f, depth+1);
809                 }
810         }
811         tc->flags &= ~TALLOC_FLAG_LOOP;
812 }
813
814 /*
815   report on memory usage by all children of a pointer, giving a full tree view
816 */
817 void talloc_report_full(const void *ptr, FILE *f)
818 {
819         if (ptr == NULL) {
820                 ptr = null_context;
821         }
822         if (ptr == NULL) return;
823
824         fprintf(f,"full talloc report on '%s' (total %lu bytes in %lu blocks)\n", 
825                 talloc_get_name(ptr), 
826                 (unsigned long)talloc_total_size(ptr),
827                 (unsigned long)talloc_total_blocks(ptr));
828
829         talloc_report_depth(ptr, f, 1);
830         fflush(f);
831 }
832
833 /*
834   report on memory usage by all children of a pointer
835 */
836 void talloc_report(const void *ptr, FILE *f)
837 {
838         struct talloc_chunk *c, *tc;
839
840         if (ptr == NULL) {
841                 ptr = null_context;
842         }
843         if (ptr == NULL) return;
844        
845         fprintf(f,"talloc report on '%s' (total %lu bytes in %lu blocks)\n", 
846                 talloc_get_name(ptr), 
847                 (unsigned long)talloc_total_size(ptr),
848                 (unsigned long)talloc_total_blocks(ptr));
849
850         tc = talloc_chunk_from_ptr(ptr);
851
852         for (c=tc->child;c;c=c->next) {
853                 fprintf(f, "\t%-30s contains %6lu bytes in %3lu blocks\n", 
854                         talloc_get_name(TC_PTR_FROM_CHUNK(c)),
855                         (unsigned long)talloc_total_size(TC_PTR_FROM_CHUNK(c)),
856                         (unsigned long)talloc_total_blocks(TC_PTR_FROM_CHUNK(c)));
857         }
858         fflush(f);
859 }
860
861 /*
862   report on any memory hanging off the null context
863 */
864 static void talloc_report_null(void)
865 {
866         if (talloc_total_size(null_context) != 0) {
867                 talloc_report(null_context, stderr);
868         }
869 }
870
871 /*
872   report on any memory hanging off the null context
873 */
874 static void talloc_report_null_full(void)
875 {
876         if (talloc_total_size(null_context) != 0) {
877                 talloc_report_full(null_context, stderr);
878         }
879 }
880
881 /*
882   enable tracking of the NULL context
883 */
884 void talloc_enable_null_tracking(void)
885 {
886         if (null_context == NULL) {
887                 null_context = talloc_named_const(NULL, 0, "null_context");
888         }
889 }
890
891 #ifdef _SAMBA_BUILD_
892 /* Ugly calls to Samba-specific sprintf_append... JRA. */
893
894 /*
895   report on memory usage by all children of a pointer, giving a full tree view
896 */
897 static void talloc_report_depth_str(const void *ptr, char **pps, ssize_t *plen, size_t *pbuflen, int depth)
898 {
899         struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
900
901         if (tc->flags & TALLOC_FLAG_LOOP) {
902                 return;
903         }
904
905         tc->flags |= TALLOC_FLAG_LOOP;
906
907         for (c=tc->child;c;c=c->next) {
908                 if (c->name == TALLOC_MAGIC_REFERENCE) {
909                         struct talloc_reference_handle *handle = TC_PTR_FROM_CHUNK(c);
910                         const char *name2 = talloc_get_name(handle->ptr);
911
912                         sprintf_append(NULL, pps, plen, pbuflen,
913                                 "%*sreference to: %s\n", depth*4, "", name2);
914
915                 } else {
916                         const char *name = talloc_get_name(TC_PTR_FROM_CHUNK(c));
917
918                         sprintf_append(NULL, pps, plen, pbuflen,
919                                 "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n", 
920                                 depth*4, "",
921                                 name,
922                                 (unsigned long)talloc_total_size(TC_PTR_FROM_CHUNK(c)),
923                                 (unsigned long)talloc_total_blocks(TC_PTR_FROM_CHUNK(c)),
924                                 talloc_reference_count(TC_PTR_FROM_CHUNK(c)));
925
926                         talloc_report_depth_str(TC_PTR_FROM_CHUNK(c), pps, plen, pbuflen, depth+1);
927                 }
928         }
929         tc->flags &= ~TALLOC_FLAG_LOOP;
930 }
931
932 /*
933   report on memory usage by all children of a pointer
934 */
935 char *talloc_describe_all(void)
936 {
937         ssize_t len = 0;
938         size_t buflen = 512;
939         char *s = NULL;
940
941         if (null_context == NULL) {
942                 return NULL;
943         }
944
945         sprintf_append(NULL, &s, &len, &buflen,
946                 "full talloc report on '%s' (total %lu bytes in %lu blocks)\n", 
947                 talloc_get_name(null_context), 
948                 (unsigned long)talloc_total_size(null_context),
949                 (unsigned long)talloc_total_blocks(null_context));
950
951         if (!s) {
952                 return NULL;
953         }
954         talloc_report_depth_str(null_context, &s, &len, &buflen, 1);
955         return s;
956 }
957 #endif
958
959 /*
960   enable leak reporting on exit
961 */
962 void talloc_enable_leak_report(void)
963 {
964         talloc_enable_null_tracking();
965         atexit(talloc_report_null);
966 }
967
968 /*
969   enable full leak reporting on exit
970 */
971 void talloc_enable_leak_report_full(void)
972 {
973         talloc_enable_null_tracking();
974         atexit(talloc_report_null_full);
975 }
976
977 /* 
978    talloc and zero memory. 
979 */
980 void *_talloc_zero(const void *ctx, size_t size, const char *name)
981 {
982         void *p = talloc_named_const(ctx, size, name);
983
984         if (p) {
985                 memset(p, '\0', size);
986         }
987
988         return p;
989 }
990
991
992 /*
993   memdup with a talloc. 
994 */
995 void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name)
996 {
997         void *newp = talloc_named_const(t, size, name);
998
999         if (newp) {
1000                 memcpy(newp, p, size);
1001         }
1002
1003         return newp;
1004 }
1005
1006 /*
1007   strdup with a talloc 
1008 */
1009 char *talloc_strdup(const void *t, const char *p)
1010 {
1011         char *ret;
1012         if (!p) {
1013                 return NULL;
1014         }
1015         ret = talloc_memdup(t, p, strlen(p) + 1);
1016         if (ret) {
1017                 talloc_set_name_const(ret, ret);
1018         }
1019         return ret;
1020 }
1021
1022 /*
1023  append to a talloced string 
1024 */
1025 char *talloc_append_string(const void *t, char *orig, const char *append)
1026 {
1027         char *ret;
1028         size_t olen = strlen(orig);
1029         size_t alenz = strlen(append) + 1;
1030
1031         if (!append)
1032                 return orig;
1033
1034         ret = talloc_realloc(t, orig, char, olen + alenz);
1035         if (!ret)
1036                 return NULL;
1037
1038         /* append the string with the trailing \0 */
1039         memcpy(&ret[olen], append, alenz);
1040
1041         return ret;
1042 }
1043
1044 /*
1045   strndup with a talloc 
1046 */
1047 char *talloc_strndup(const void *t, const char *p, size_t n)
1048 {
1049         size_t len;
1050         char *ret;
1051
1052         for (len=0; len<n && p[len]; len++) ;
1053
1054         ret = _talloc(t, len + 1);
1055         if (!ret) { return NULL; }
1056         memcpy(ret, p, len);
1057         ret[len] = 0;
1058         talloc_set_name_const(ret, ret);
1059         return ret;
1060 }
1061
1062 #ifndef VA_COPY
1063 #ifdef HAVE_VA_COPY
1064 #define VA_COPY(dest, src) va_copy(dest, src)
1065 #elif defined(HAVE___VA_COPY)
1066 #define VA_COPY(dest, src) __va_copy(dest, src)
1067 #else
1068 #define VA_COPY(dest, src) (dest) = (src)
1069 #endif
1070 #endif
1071
1072 char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
1073 {       
1074         int len;
1075         char *ret;
1076         va_list ap2;
1077         
1078         VA_COPY(ap2, ap);
1079
1080         len = vsnprintf(NULL, 0, fmt, ap2);
1081
1082         ret = _talloc(t, len+1);
1083         if (ret) {
1084                 VA_COPY(ap2, ap);
1085                 vsnprintf(ret, len+1, fmt, ap2);
1086                 talloc_set_name_const(ret, ret);
1087         }
1088
1089         return ret;
1090 }
1091
1092
1093 /*
1094   Perform string formatting, and return a pointer to newly allocated
1095   memory holding the result, inside a memory pool.
1096  */
1097 char *talloc_asprintf(const void *t, const char *fmt, ...)
1098 {
1099         va_list ap;
1100         char *ret;
1101
1102         va_start(ap, fmt);
1103         ret = talloc_vasprintf(t, fmt, ap);
1104         va_end(ap);
1105         return ret;
1106 }
1107
1108
1109 /**
1110  * Realloc @p s to append the formatted result of @p fmt and @p ap,
1111  * and return @p s, which may have moved.  Good for gradually
1112  * accumulating output into a string buffer.
1113  **/
1114
1115 static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
1116
1117 static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
1118 {       
1119         struct talloc_chunk *tc;
1120         int len, s_len;
1121         va_list ap2;
1122
1123         if (s == NULL) {
1124                 return talloc_vasprintf(NULL, fmt, ap);
1125         }
1126
1127         tc = talloc_chunk_from_ptr(s);
1128
1129         VA_COPY(ap2, ap);
1130
1131         s_len = tc->size - 1;
1132         len = vsnprintf(NULL, 0, fmt, ap2);
1133
1134         s = talloc_realloc(NULL, s, char, s_len + len+1);
1135         if (!s) return NULL;
1136
1137         VA_COPY(ap2, ap);
1138
1139         vsnprintf(s+s_len, len+1, fmt, ap2);
1140         talloc_set_name_const(s, s);
1141
1142         return s;
1143 }
1144
1145 /*
1146   Realloc @p s to append the formatted result of @p fmt and return @p
1147   s, which may have moved.  Good for gradually accumulating output
1148   into a string buffer.
1149  */
1150 char *talloc_asprintf_append(char *s, const char *fmt, ...)
1151 {
1152         va_list ap;
1153
1154         va_start(ap, fmt);
1155         s = talloc_vasprintf_append(s, fmt, ap);
1156         va_end(ap);
1157         return s;
1158 }
1159
1160 /*
1161   alloc an array, checking for integer overflow in the array size
1162 */
1163 void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
1164 {
1165         if (count >= MAX_TALLOC_SIZE/el_size) {
1166                 return NULL;
1167         }
1168         return talloc_named_const(ctx, el_size * count, name);
1169 }
1170
1171 /*
1172   alloc an zero array, checking for integer overflow in the array size
1173 */
1174 void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name)
1175 {
1176         if (count >= MAX_TALLOC_SIZE/el_size) {
1177                 return NULL;
1178         }
1179         return _talloc_zero(ctx, el_size * count, name);
1180 }
1181
1182
1183 /*
1184   realloc an array, checking for integer overflow in the array size
1185 */
1186 void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
1187 {
1188         if (count >= MAX_TALLOC_SIZE/el_size) {
1189                 return NULL;
1190         }
1191         return _talloc_realloc(ctx, ptr, el_size * count, name);
1192 }
1193
1194 /*
1195   a function version of talloc_realloc(), so it can be passed as a function pointer
1196   to libraries that want a realloc function (a realloc function encapsulates
1197   all the basic capabilities of an allocation library, which is why this is useful)
1198 */
1199 void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
1200 {
1201         return _talloc_realloc(context, ptr, size, NULL);
1202 }
1203
1204
1205 static void talloc_autofree(void)
1206 {
1207         talloc_free(cleanup_context);
1208         cleanup_context = NULL;
1209 }
1210
1211 /*
1212   return a context which will be auto-freed on exit
1213   this is useful for reducing the noise in leak reports
1214 */
1215 void *talloc_autofree_context(void)
1216 {
1217         if (cleanup_context == NULL) {
1218                 cleanup_context = talloc_named_const(NULL, 0, "autofree_context");
1219                 atexit(talloc_autofree);
1220         }
1221         return cleanup_context;
1222 }
1223
1224 size_t talloc_get_size(const void *context)
1225 {
1226         struct talloc_chunk *tc;
1227
1228         if (context == NULL)
1229                 return 0;
1230
1231         tc = talloc_chunk_from_ptr(context);
1232
1233         return tc->size;
1234 }
1235
1236 /*
1237   find a parent of this context that has the given name, if any
1238 */
1239 void *talloc_find_parent_byname(const void *context, const char *name)
1240 {
1241         struct talloc_chunk *tc;
1242
1243         if (context == NULL) {
1244                 return NULL;
1245         }
1246
1247         tc = talloc_chunk_from_ptr(context);
1248         while (tc) {
1249                 if (tc->name && strcmp(tc->name, name) == 0) {
1250                         return TC_PTR_FROM_CHUNK(tc);
1251                 }
1252                 while (tc && tc->prev) tc = tc->prev;
1253                 tc = tc->parent;
1254         }
1255         return NULL;
1256 }
1257
1258 /*
1259   show the parentage of a context
1260 */
1261 void talloc_show_parents(const void *context, FILE *file)
1262 {
1263         struct talloc_chunk *tc;
1264
1265         if (context == NULL) {
1266                 fprintf(file, "talloc no parents for NULL\n");
1267                 return;
1268         }
1269
1270         tc = talloc_chunk_from_ptr(context);
1271         fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
1272         while (tc) {
1273                 fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)));
1274                 while (tc && tc->prev) tc = tc->prev;
1275                 tc = tc->parent;
1276         }
1277 }