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