source: trunk/packages/xen-3.1/xen-3.1/tools/xenstore/talloc.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 19 years ago

Add xen and xen-common

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