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