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