source: trunk/lib/talloc.c @ 147

Last change on this file since 147 was 147, checked in by tim, 15 years ago

added talloc library

incorporated talloc into winsec and lru_cache modules

introduced talloc into SK caching system

  • Property svn:keywords set to Id
File size: 37.1 KB
RevLine 
[147]1/*
2   Samba Unix SMB/CIFS implementation.
3
4   Samba trivial allocation library - new interface
5     inspired by http://swapped.cc/halloc/
6
7   NOTE: Please read talloc_guide.txt for full documentation
8
9   Copyright (C) Andrew Tridgell 2004
10   Copyright (C) Stefan Metzmacher 2006
11   Copyright (C) Timothy D. Morgan 2009
12 
13     ** NOTE! The following LGPL license applies to the talloc library.
14     ** This does NOT imply that all of reglookup is released under the LGPL
15   
16   This library is free software; you can redistribute it and/or
17   modify it under the terms of the GNU Lesser General Public
18   License as published by the Free Software Foundation; either
19   version 3 of the License, or (at your option) any later version.
20
21   This library is distributed in the hope that it will be useful,
22   but WITHOUT ANY WARRANTY; without even the implied warranty of
23   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24   Lesser General Public License for more details.
25
26   You should have received a copy of the GNU Lesser General Public
27   License along with this library; if not, see <http://www.gnu.org/licenses/>.
28*/
29/* $Id: talloc.c 147 2009-02-22 19:31:52Z tim $ */
30
31#include "talloc.h"
32
33/* use this to force every realloc to change the pointer, to stress test
34   code that might not cope */
35#define ALWAYS_REALLOC 0
36
37
38#define MAX_TALLOC_SIZE 0x10000000
39#define TALLOC_MAGIC 0xe814ec70
40#define TALLOC_FLAG_FREE 0x01
41#define TALLOC_FLAG_LOOP 0x02
42#define TALLOC_FLAG_POOL 0x04           /* This is a talloc pool */
43#define TALLOC_FLAG_POOLMEM 0x08        /* This is allocated in a pool */
44#define TALLOC_MAGIC_REFERENCE ((const char *)1)
45
46/* by default we abort when given a bad pointer (such as when talloc_free() is called
47   on a pointer that came from malloc() */
48#ifndef TALLOC_ABORT
49#define TALLOC_ABORT(reason) abort()
50#endif
51
52#ifndef discard_const_p
53#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
54# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
55#else
56# define discard_const_p(type, ptr) ((type *)(ptr))
57#endif
58#endif
59
60/* these macros gain us a few percent of speed on gcc */
61#if (__GNUC__ >= 3)
62/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1
63   as its first argument */
64#define likely(x)   __builtin_expect(!!(x), 1)
65#define unlikely(x) __builtin_expect(!!(x), 0)
66#else
67#define likely(x) x
68#define unlikely(x) x
69#endif
70
71/* this null_context is only used if talloc_enable_leak_report() or
72   talloc_enable_leak_report_full() is called, otherwise it remains
73   NULL
74*/
75static void *null_context;
76static void *autofree_context;
77
78struct talloc_reference_handle {
79        struct talloc_reference_handle *next, *prev;
80        void *ptr;
81};
82
83typedef int (*talloc_destructor_t)(void *);
84
85struct talloc_chunk {
86        struct talloc_chunk *next, *prev;
87        struct talloc_chunk *parent, *child;
88        struct talloc_reference_handle *refs;
89        talloc_destructor_t destructor;
90        const char *name;
91        size_t size;
92        unsigned flags;
93
94        /*
95         * "pool" has dual use:
96         *
97         * For the talloc pool itself (i.e. TALLOC_FLAG_POOL is set), "pool"
98         * marks the end of the currently allocated area.
99         *
100         * For members of the pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool"
101         * is a pointer to the struct talloc_chunk of the pool that it was
102         * allocated from. This way children can quickly find the pool to chew
103         * from.
104         */
105        void *pool;
106};
107
108/* 16 byte alignment seems to keep everyone happy */
109#define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15)
110#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc))
111
112static void talloc_abort_double_free(void)
113{
114        TALLOC_ABORT("Bad talloc magic value - double free"); 
115}
116
117static void talloc_abort_unknown_value(void)
118{
119        TALLOC_ABORT("Bad talloc magic value - unknown value"); 
120}
121
122/* panic if we get a bad magic value */
123static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
124{
125        const char *pp = (const char *)ptr;
126        struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE);
127        if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) { 
128                if (tc->flags & TALLOC_FLAG_FREE) {
129                        talloc_abort_double_free();
130                } else {
131                        talloc_abort_unknown_value();
132                }
133        }
134        return tc;
135}
136
137/* hook into the front of the list */
138#define _TLIST_ADD(list, p) \
139do { \
140        if (!(list)) { \
141                (list) = (p); \
142                (p)->next = (p)->prev = NULL; \
143        } else { \
144                (list)->prev = (p); \
145                (p)->next = (list); \
146                (p)->prev = NULL; \
147                (list) = (p); \
148        }\
149} while (0)
150
151/* remove an element from a list - element doesn't have to be in list. */
152#define _TLIST_REMOVE(list, p) \
153do { \
154        if ((p) == (list)) { \
155                (list) = (p)->next; \
156                if (list) (list)->prev = NULL; \
157        } else { \
158                if ((p)->prev) (p)->prev->next = (p)->next; \
159                if ((p)->next) (p)->next->prev = (p)->prev; \
160        } \
161        if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
162} while (0)
163
164
165/*
166  return the parent chunk of a pointer
167*/
168static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr)
169{
170        struct talloc_chunk *tc;
171
172        if (unlikely(ptr == NULL)) {
173                return NULL;
174        }
175
176        tc = talloc_chunk_from_ptr(ptr);
177        while (tc->prev) tc=tc->prev;
178
179        return tc->parent;
180}
181
182void *talloc_parent(const void *ptr)
183{
184        struct talloc_chunk *tc = talloc_parent_chunk(ptr);
185        return tc? TC_PTR_FROM_CHUNK(tc) : NULL;
186}
187
188/*
189  find parents name
190*/
191const char *talloc_parent_name(const void *ptr)
192{
193        struct talloc_chunk *tc = talloc_parent_chunk(ptr);
194        return tc? tc->name : NULL;
195}
196
197/*
198  A pool carries an in-pool object count count in the first 16 bytes.
199  bytes. This is done to support talloc_steal() to a parent outside of the
200  pool. The count includes the pool itself, so a talloc_free() on a pool will
201  only destroy the pool if the count has dropped to zero. A talloc_free() of a
202  pool member will reduce the count, and eventually also call free(3) on the
203  pool memory.
204
205  The object count is not put into "struct talloc_chunk" because it is only
206  relevant for talloc pools and the alignment to 16 bytes would increase the
207  memory footprint of each talloc chunk by those 16 bytes.
208*/
209
210#define TALLOC_POOL_HDR_SIZE 16
211
212static unsigned int *talloc_pool_objectcount(struct talloc_chunk *tc)
213{
214        return (unsigned int *)((char *)tc + sizeof(struct talloc_chunk));
215}
216
217/*
218  Allocate from a pool
219*/
220
221static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent,
222                                              size_t size)
223{
224        struct talloc_chunk *pool_ctx = NULL;
225        size_t space_left;
226        struct talloc_chunk *result;
227        size_t chunk_size;
228
229        if (parent == NULL) {
230                return NULL;
231        }
232
233        if (parent->flags & TALLOC_FLAG_POOL) {
234                pool_ctx = parent;
235        }
236        else if (parent->flags & TALLOC_FLAG_POOLMEM) {
237                pool_ctx = (struct talloc_chunk *)parent->pool;
238        }
239
240        if (pool_ctx == NULL) {
241                return NULL;
242        }
243
244        space_left = ((char *)pool_ctx + TC_HDR_SIZE + pool_ctx->size)
245                - ((char *)pool_ctx->pool);
246
247        /*
248         * Align size to 16 bytes
249         */
250        chunk_size = ((size + 15) & ~15);
251
252        if (space_left < chunk_size) {
253                return NULL;
254        }
255
256        result = (struct talloc_chunk *)pool_ctx->pool;
257
258#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
259        VALGRIND_MAKE_MEM_UNDEFINED(result, size);
260#endif
261
262        pool_ctx->pool = (void *)((char *)result + chunk_size);
263
264        result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM;
265        result->pool = pool_ctx;
266
267        *talloc_pool_objectcount(pool_ctx) += 1;
268
269        return result;
270}
271
272/*
273   Allocate a bit of memory as a child of an existing pointer
274*/
275static inline void *__talloc(const void *context, size_t size)
276{
277        struct talloc_chunk *tc = NULL;
278
279        if (unlikely(context == NULL)) {
280                context = null_context;
281        }
282
283        if (unlikely(size >= MAX_TALLOC_SIZE)) {
284                return NULL;
285        }
286
287        if (context != NULL) {
288                tc = talloc_alloc_pool(talloc_chunk_from_ptr(context),
289                                       TC_HDR_SIZE+size);
290        }
291
292        if (tc == NULL) {
293                tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size);
294                if (unlikely(tc == NULL)) return NULL;
295                tc->flags = TALLOC_MAGIC;
296                tc->pool  = NULL;
297        }
298
299        tc->size = size;
300        tc->destructor = NULL;
301        tc->child = NULL;
302        tc->name = NULL;
303        tc->refs = NULL;
304
305        if (likely(context)) {
306                struct talloc_chunk *parent = talloc_chunk_from_ptr(context);
307
308                if (parent->child) {
309                        parent->child->parent = NULL;
310                        tc->next = parent->child;
311                        tc->next->prev = tc;
312                } else {
313                        tc->next = NULL;
314                }
315                tc->parent = parent;
316                tc->prev = NULL;
317                parent->child = tc;
318        } else {
319                tc->next = tc->prev = tc->parent = NULL;
320        }
321
322        return TC_PTR_FROM_CHUNK(tc);
323}
324
325/*
326 * Create a talloc pool
327 */
328
329void *talloc_pool(const void *context, size_t size)
330{
331        void *result = __talloc(context, size + TALLOC_POOL_HDR_SIZE);
332        struct talloc_chunk *tc;
333
334        if (unlikely(result == NULL)) {
335                return NULL;
336        }
337
338        tc = talloc_chunk_from_ptr(result);
339
340        tc->flags |= TALLOC_FLAG_POOL;
341        tc->pool = (char *)result + TALLOC_POOL_HDR_SIZE;
342
343        *talloc_pool_objectcount(tc) = 1;
344
345#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
346        VALGRIND_MAKE_MEM_NOACCESS(tc->pool, size);
347#endif
348
349        return result;
350}
351
352/*
353  setup a destructor to be called on free of a pointer
354  the destructor should return 0 on success, or -1 on failure.
355  if the destructor fails then the free is failed, and the memory can
356  be continued to be used
357*/
358void _talloc_set_destructor(const void *ptr, int (*destructor)(void *))
359{
360        struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
361        tc->destructor = destructor;
362}
363
364/*
365  increase the reference count on a piece of memory.
366*/
367int talloc_increase_ref_count(const void *ptr)
368{
369        if (unlikely(!talloc_reference(null_context, ptr))) {
370                return -1;
371        }
372        return 0;
373}
374
375/*
376  helper for talloc_reference()
377
378  this is referenced by a function pointer and should not be inline
379*/
380static int talloc_reference_destructor(struct talloc_reference_handle *handle)
381{
382        struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr);
383        _TLIST_REMOVE(ptr_tc->refs, handle);
384        return 0;
385}
386
387/*
388   more efficient way to add a name to a pointer - the name must point to a
389   true string constant
390*/
391static inline void _talloc_set_name_const(const void *ptr, const char *name)
392{
393        struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
394        tc->name = name;
395}
396
397/*
398  internal talloc_named_const()
399*/
400static inline void *_talloc_named_const(const void *context, size_t size, const char *name)
401{
402        void *ptr;
403
404        ptr = __talloc(context, size);
405        if (unlikely(ptr == NULL)) {
406                return NULL;
407        }
408
409        _talloc_set_name_const(ptr, name);
410
411        return ptr;
412}
413
414/*
415  make a secondary reference to a pointer, hanging off the given context.
416  the pointer remains valid until both the original caller and this given
417  context are freed.
418 
419  the major use for this is when two different structures need to reference the
420  same underlying data, and you want to be able to free the two instances separately,
421  and in either order
422*/
423void *_talloc_reference(const void *context, const void *ptr)
424{
425        struct talloc_chunk *tc;
426        struct talloc_reference_handle *handle;
427        if (unlikely(ptr == NULL)) return NULL;
428
429        tc = talloc_chunk_from_ptr(ptr);
430        handle = (struct talloc_reference_handle *)_talloc_named_const(context,
431                                                   sizeof(struct talloc_reference_handle),
432                                                   TALLOC_MAGIC_REFERENCE);
433        if (unlikely(handle == NULL)) return NULL;
434
435        /* note that we hang the destructor off the handle, not the
436           main context as that allows the caller to still setup their
437           own destructor on the context if they want to */
438        talloc_set_destructor(handle, talloc_reference_destructor);
439        handle->ptr = discard_const_p(void, ptr);
440        _TLIST_ADD(tc->refs, handle);
441        return handle->ptr;
442}
443
444
445/*
446   internal talloc_free call
447*/
448static inline int _talloc_free(void *ptr)
449{
450        struct talloc_chunk *tc;
451
452        if (unlikely(ptr == NULL)) {
453                return -1;
454        }
455
456        tc = talloc_chunk_from_ptr(ptr);
457
458        if (unlikely(tc->refs)) {
459                int is_child;
460                /* check this is a reference from a child or grantchild
461                 * back to it's parent or grantparent
462                 *
463                 * in that case we need to remove the reference and
464                 * call another instance of talloc_free() on the current
465                 * pointer.
466                 */
467                is_child = talloc_is_parent(tc->refs, ptr);
468                _talloc_free(tc->refs);
469                if (is_child) {
470                        return _talloc_free(ptr);
471                }
472                return -1;
473        }
474
475        if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) {
476                /* we have a free loop - stop looping */
477                return 0;
478        }
479
480        if (unlikely(tc->destructor)) {
481                talloc_destructor_t d = tc->destructor;
482                if (d == (talloc_destructor_t)-1) {
483                        return -1;
484                }
485                tc->destructor = (talloc_destructor_t)-1;
486                if (d(ptr) == -1) {
487                        tc->destructor = d;
488                        return -1;
489                }
490                tc->destructor = NULL;
491        }
492
493        if (tc->parent) {
494                _TLIST_REMOVE(tc->parent->child, tc);
495                if (tc->parent->child) {
496                        tc->parent->child->parent = tc->parent;
497                }
498        } else {
499                if (tc->prev) tc->prev->next = tc->next;
500                if (tc->next) tc->next->prev = tc->prev;
501        }
502
503        tc->flags |= TALLOC_FLAG_LOOP;
504
505        while (tc->child) {
506                /* we need to work out who will own an abandoned child
507                   if it cannot be freed. In priority order, the first
508                   choice is owner of any remaining reference to this
509                   pointer, the second choice is our parent, and the
510                   final choice is the null context. */
511                void *child = TC_PTR_FROM_CHUNK(tc->child);
512                const void *new_parent = null_context;
513                if (unlikely(tc->child->refs)) {
514                        struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
515                        if (p) new_parent = TC_PTR_FROM_CHUNK(p);
516                }
517                if (unlikely(_talloc_free(child) == -1)) {
518                        if (new_parent == null_context) {
519                                struct talloc_chunk *p = talloc_parent_chunk(ptr);
520                                if (p) new_parent = TC_PTR_FROM_CHUNK(p);
521                        }
522                        talloc_steal(new_parent, child);
523                }
524        }
525
526        tc->flags |= TALLOC_FLAG_FREE;
527
528        if (tc->flags & (TALLOC_FLAG_POOL|TALLOC_FLAG_POOLMEM)) {
529                struct talloc_chunk *pool;
530                unsigned int *pool_object_count;
531
532                pool = (tc->flags & TALLOC_FLAG_POOL)
533                        ? tc : (struct talloc_chunk *)tc->pool;
534
535                pool_object_count = talloc_pool_objectcount(pool);
536
537                if (*pool_object_count == 0) {
538                        TALLOC_ABORT("Pool object count zero!");
539                }
540
541                *pool_object_count -= 1;
542
543                if (*pool_object_count == 0) {
544                        free(pool);
545                }
546        }
547        else {
548                free(tc);
549        }
550        return 0;
551}
552
553/*
554   move a lump of memory from one talloc context to another return the
555   ptr on success, or NULL if it could not be transferred.
556   passing NULL as ptr will always return NULL with no side effects.
557*/
558void *_talloc_steal(const void *new_ctx, const void *ptr)
559{
560        struct talloc_chunk *tc, *new_tc;
561
562        if (unlikely(!ptr)) {
563                return NULL;
564        }
565
566        if (unlikely(new_ctx == NULL)) {
567                new_ctx = null_context;
568        }
569
570        tc = talloc_chunk_from_ptr(ptr);
571
572        if (unlikely(new_ctx == NULL)) {
573                if (tc->parent) {
574                        _TLIST_REMOVE(tc->parent->child, tc);
575                        if (tc->parent->child) {
576                                tc->parent->child->parent = tc->parent;
577                        }
578                } else {
579                        if (tc->prev) tc->prev->next = tc->next;
580                        if (tc->next) tc->next->prev = tc->prev;
581                }
582               
583                tc->parent = tc->next = tc->prev = NULL;
584                return discard_const_p(void, ptr);
585        }
586
587        new_tc = talloc_chunk_from_ptr(new_ctx);
588
589        if (unlikely(tc == new_tc || tc->parent == new_tc)) {
590                return discard_const_p(void, ptr);
591        }
592
593        if (tc->parent) {
594                _TLIST_REMOVE(tc->parent->child, tc);
595                if (tc->parent->child) {
596                        tc->parent->child->parent = tc->parent;
597                }
598        } else {
599                if (tc->prev) tc->prev->next = tc->next;
600                if (tc->next) tc->next->prev = tc->prev;
601        }
602
603        tc->parent = new_tc;
604        if (new_tc->child) new_tc->child->parent = NULL;
605        _TLIST_ADD(new_tc->child, tc);
606
607        return discard_const_p(void, ptr);
608}
609
610
611
612/*
613  remove a secondary reference to a pointer. This undo's what
614  talloc_reference() has done. The context and pointer arguments
615  must match those given to a talloc_reference()
616*/
617static inline int talloc_unreference(const void *context, const void *ptr)
618{
619        struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
620        struct talloc_reference_handle *h;
621
622        if (unlikely(context == NULL)) {
623                context = null_context;
624        }
625
626        for (h=tc->refs;h;h=h->next) {
627                struct talloc_chunk *p = talloc_parent_chunk(h);
628                if (p == NULL) {
629                        if (context == NULL) break;
630                } else if (TC_PTR_FROM_CHUNK(p) == context) {
631                        break;
632                }
633        }
634        if (h == NULL) {
635                return -1;
636        }
637
638        return _talloc_free(h);
639}
640
641/*
642  remove a specific parent context from a pointer. This is a more
643  controlled varient of talloc_free()
644*/
645int talloc_unlink(const void *context, void *ptr)
646{
647        struct talloc_chunk *tc_p, *new_p;
648        void *new_parent;
649
650        if (ptr == NULL) {
651                return -1;
652        }
653
654        if (context == NULL) {
655                context = null_context;
656        }
657
658        if (talloc_unreference(context, ptr) == 0) {
659                return 0;
660        }
661
662        if (context == NULL) {
663                if (talloc_parent_chunk(ptr) != NULL) {
664                        return -1;
665                }
666        } else {
667                if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) {
668                        return -1;
669                }
670        }
671       
672        tc_p = talloc_chunk_from_ptr(ptr);
673
674        if (tc_p->refs == NULL) {
675                return _talloc_free(ptr);
676        }
677
678        new_p = talloc_parent_chunk(tc_p->refs);
679        if (new_p) {
680                new_parent = TC_PTR_FROM_CHUNK(new_p);
681        } else {
682                new_parent = NULL;
683        }
684
685        if (talloc_unreference(new_parent, ptr) != 0) {
686                return -1;
687        }
688
689        talloc_steal(new_parent, ptr);
690
691        return 0;
692}
693
694/*
695  add a name to an existing pointer - va_list version
696*/
697static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
698
699static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
700{
701        struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
702        tc->name = talloc_vasprintf(ptr, fmt, ap);
703        if (likely(tc->name)) {
704                _talloc_set_name_const(tc->name, ".name");
705        }
706        return tc->name;
707}
708
709/*
710  add a name to an existing pointer
711*/
712const char *talloc_set_name(const void *ptr, const char *fmt, ...)
713{
714        const char *name;
715        va_list ap;
716        va_start(ap, fmt);
717        name = talloc_set_name_v(ptr, fmt, ap);
718        va_end(ap);
719        return name;
720}
721
722
723/*
724  create a named talloc pointer. Any talloc pointer can be named, and
725  talloc_named() operates just like talloc() except that it allows you
726  to name the pointer.
727*/
728void *talloc_named(const void *context, size_t size, const char *fmt, ...)
729{
730        va_list ap;
731        void *ptr;
732        const char *name;
733
734        ptr = __talloc(context, size);
735        if (unlikely(ptr == NULL)) return NULL;
736
737        va_start(ap, fmt);
738        name = talloc_set_name_v(ptr, fmt, ap);
739        va_end(ap);
740
741        if (unlikely(name == NULL)) {
742                _talloc_free(ptr);
743                return NULL;
744        }
745
746        return ptr;
747}
748
749/*
750  return the name of a talloc ptr, or "UNNAMED"
751*/
752const char *talloc_get_name(const void *ptr)
753{
754        struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
755        if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) {
756                return ".reference";
757        }
758        if (likely(tc->name)) {
759                return tc->name;
760        }
761        return "UNNAMED";
762}
763
764
765/*
766  check if a pointer has the given name. If it does, return the pointer,
767  otherwise return NULL
768*/
769void *talloc_check_name(const void *ptr, const char *name)
770{
771        const char *pname;
772        if (unlikely(ptr == NULL)) return NULL;
773        pname = talloc_get_name(ptr);
774        if (likely(pname == name || strcmp(pname, name) == 0)) {
775                return discard_const_p(void, ptr);
776        }
777        return NULL;
778}
779
780
781/*
782  this is for compatibility with older versions of talloc
783*/
784void *talloc_init(const char *fmt, ...)
785{
786        va_list ap;
787        void *ptr;
788        const char *name;
789
790        /*
791         * samba3 expects talloc_report_depth_cb(NULL, ...)
792         * reports all talloc'ed memory, so we need to enable
793         * null_tracking
794         */
795        talloc_enable_null_tracking();
796
797        ptr = __talloc(NULL, 0);
798        if (unlikely(ptr == NULL)) return NULL;
799
800        va_start(ap, fmt);
801        name = talloc_set_name_v(ptr, fmt, ap);
802        va_end(ap);
803
804        if (unlikely(name == NULL)) {
805                _talloc_free(ptr);
806                return NULL;
807        }
808
809        return ptr;
810}
811
812/*
813  this is a replacement for the Samba3 talloc_destroy_pool functionality. It
814  should probably not be used in new code. It's in here to keep the talloc
815  code consistent across Samba 3 and 4.
816*/
817void talloc_free_children(void *ptr)
818{
819        struct talloc_chunk *tc;
820
821        if (unlikely(ptr == NULL)) {
822                return;
823        }
824
825        tc = talloc_chunk_from_ptr(ptr);
826
827        while (tc->child) {
828                /* we need to work out who will own an abandoned child
829                   if it cannot be freed. In priority order, the first
830                   choice is owner of any remaining reference to this
831                   pointer, the second choice is our parent, and the
832                   final choice is the null context. */
833                void *child = TC_PTR_FROM_CHUNK(tc->child);
834                const void *new_parent = null_context;
835                if (unlikely(tc->child->refs)) {
836                        struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
837                        if (p) new_parent = TC_PTR_FROM_CHUNK(p);
838                }
839                if (unlikely(_talloc_free(child) == -1)) {
840                        if (new_parent == null_context) {
841                                struct talloc_chunk *p = talloc_parent_chunk(ptr);
842                                if (p) new_parent = TC_PTR_FROM_CHUNK(p);
843                        }
844                        talloc_steal(new_parent, child);
845                }
846        }
847
848        if ((tc->flags & TALLOC_FLAG_POOL)
849            && (*talloc_pool_objectcount(tc) == 1)) {
850                tc->pool = ((char *)tc + TC_HDR_SIZE + TALLOC_POOL_HDR_SIZE);
851#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
852                VALGRIND_MAKE_MEM_NOACCESS(
853                        tc->pool, tc->size - TALLOC_POOL_HDR_SIZE);
854#endif
855        }
856}
857
858/*
859   Allocate a bit of memory as a child of an existing pointer
860*/
861void *_talloc(const void *context, size_t size)
862{
863        return __talloc(context, size);
864}
865
866/*
867  externally callable talloc_set_name_const()
868*/
869void talloc_set_name_const(const void *ptr, const char *name)
870{
871        _talloc_set_name_const(ptr, name);
872}
873
874/*
875  create a named talloc pointer. Any talloc pointer can be named, and
876  talloc_named() operates just like talloc() except that it allows you
877  to name the pointer.
878*/
879void *talloc_named_const(const void *context, size_t size, const char *name)
880{
881        return _talloc_named_const(context, size, name);
882}
883
884/*
885   free a talloc pointer. This also frees all child pointers of this
886   pointer recursively
887
888   return 0 if the memory is actually freed, otherwise -1. The memory
889   will not be freed if the ref_count is > 1 or the destructor (if
890   any) returns non-zero
891*/
892int talloc_free(void *ptr)
893{
894        return _talloc_free(ptr);
895}
896
897
898
899/*
900  A talloc version of realloc. The context argument is only used if
901  ptr is NULL
902*/
903void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name)
904{
905        struct talloc_chunk *tc;
906        void *new_ptr;
907        bool malloced = false;
908
909        /* size zero is equivalent to free() */
910        if (unlikely(size == 0)) {
911                _talloc_free(ptr);
912                return NULL;
913        }
914
915        if (unlikely(size >= MAX_TALLOC_SIZE)) {
916                return NULL;
917        }
918
919        /* realloc(NULL) is equivalent to malloc() */
920        if (ptr == NULL) {
921                return _talloc_named_const(context, size, name);
922        }
923
924        tc = talloc_chunk_from_ptr(ptr);
925
926        /* don't allow realloc on referenced pointers */
927        if (unlikely(tc->refs)) {
928                return NULL;
929        }
930
931        /* don't shrink if we have less than 1k to gain */
932        if ((size < tc->size) && ((tc->size - size) < 1024)) {
933                tc->size = size;
934                return ptr;
935        }
936
937        /* by resetting magic we catch users of the old memory */
938        tc->flags |= TALLOC_FLAG_FREE;
939
940#if ALWAYS_REALLOC
941        new_ptr = malloc(size + TC_HDR_SIZE);
942        if (new_ptr) {
943                memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE);
944                free(tc);
945        }
946#else
947        if (tc->flags & TALLOC_FLAG_POOLMEM) {
948
949                new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE);
950                *talloc_pool_objectcount((struct talloc_chunk *)
951                                         (tc->pool)) -= 1;
952
953                if (new_ptr == NULL) {
954                        new_ptr = malloc(TC_HDR_SIZE+size);
955                        malloced = true;
956                }
957
958                if (new_ptr) {
959                        memcpy(new_ptr, tc, MIN(tc->size,size) + TC_HDR_SIZE);
960                }
961        }
962        else {
963                new_ptr = realloc(tc, size + TC_HDR_SIZE);
964        }
965#endif
966        if (unlikely(!new_ptr)) {       
967                tc->flags &= ~TALLOC_FLAG_FREE; 
968                return NULL; 
969        }
970
971        tc = (struct talloc_chunk *)new_ptr;
972        tc->flags &= ~TALLOC_FLAG_FREE;
973        if (malloced) {
974                tc->flags &= ~TALLOC_FLAG_POOLMEM;
975        }
976        if (tc->parent) {
977                tc->parent->child = tc;
978        }
979        if (tc->child) {
980                tc->child->parent = tc;
981        }
982
983        if (tc->prev) {
984                tc->prev->next = tc;
985        }
986        if (tc->next) {
987                tc->next->prev = tc;
988        }
989
990        tc->size = size;
991        _talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
992
993        return TC_PTR_FROM_CHUNK(tc);
994}
995
996/*
997  a wrapper around talloc_steal() for situations where you are moving a pointer
998  between two structures, and want the old pointer to be set to NULL
999*/
1000void *_talloc_move(const void *new_ctx, const void *_pptr)
1001{
1002        const void **pptr = discard_const_p(const void *,_pptr);
1003        void *ret = _talloc_steal(new_ctx, *pptr);
1004        (*pptr) = NULL;
1005        return ret;
1006}
1007
1008/*
1009  return the total size of a talloc pool (subtree)
1010*/
1011size_t talloc_total_size(const void *ptr)
1012{
1013        size_t total = 0;
1014        struct talloc_chunk *c, *tc;
1015
1016        if (ptr == NULL) {
1017                ptr = null_context;
1018        }
1019        if (ptr == NULL) {
1020                return 0;
1021        }
1022
1023        tc = talloc_chunk_from_ptr(ptr);
1024
1025        if (tc->flags & TALLOC_FLAG_LOOP) {
1026                return 0;
1027        }
1028
1029        tc->flags |= TALLOC_FLAG_LOOP;
1030
1031        total = tc->size;
1032        for (c=tc->child;c;c=c->next) {
1033                total += talloc_total_size(TC_PTR_FROM_CHUNK(c));
1034        }
1035
1036        tc->flags &= ~TALLOC_FLAG_LOOP;
1037
1038        return total;
1039}
1040
1041/*
1042  return the total number of blocks in a talloc pool (subtree)
1043*/
1044size_t talloc_total_blocks(const void *ptr)
1045{
1046        size_t total = 0;
1047        struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
1048
1049        if (tc->flags & TALLOC_FLAG_LOOP) {
1050                return 0;
1051        }
1052
1053        tc->flags |= TALLOC_FLAG_LOOP;
1054
1055        total++;
1056        for (c=tc->child;c;c=c->next) {
1057                total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c));
1058        }
1059
1060        tc->flags &= ~TALLOC_FLAG_LOOP;
1061
1062        return total;
1063}
1064
1065/*
1066  return the number of external references to a pointer
1067*/
1068size_t talloc_reference_count(const void *ptr)
1069{
1070        struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
1071        struct talloc_reference_handle *h;
1072        size_t ret = 0;
1073
1074        for (h=tc->refs;h;h=h->next) {
1075                ret++;
1076        }
1077        return ret;
1078}
1079
1080/*
1081  report on memory usage by all children of a pointer, giving a full tree view
1082*/
1083void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
1084                            void (*callback)(const void *ptr,
1085                                             int depth, int max_depth,
1086                                             int is_ref,
1087                                             void *private_data),
1088                            void *private_data)
1089{
1090        struct talloc_chunk *c, *tc;
1091
1092        if (ptr == NULL) {
1093                ptr = null_context;
1094        }
1095        if (ptr == NULL) return;
1096
1097        tc = talloc_chunk_from_ptr(ptr);
1098
1099        if (tc->flags & TALLOC_FLAG_LOOP) {
1100                return;
1101        }
1102
1103        callback(ptr, depth, max_depth, 0, private_data);
1104
1105        if (max_depth >= 0 && depth >= max_depth) {
1106                return;
1107        }
1108
1109        tc->flags |= TALLOC_FLAG_LOOP;
1110        for (c=tc->child;c;c=c->next) {
1111                if (c->name == TALLOC_MAGIC_REFERENCE) {
1112                        struct talloc_reference_handle *h = (struct talloc_reference_handle *)TC_PTR_FROM_CHUNK(c);
1113                        callback(h->ptr, depth + 1, max_depth, 1, private_data);
1114                } else {
1115                        talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1, max_depth, callback, private_data);
1116                }
1117        }
1118        tc->flags &= ~TALLOC_FLAG_LOOP;
1119}
1120
1121static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_f)
1122{
1123        const char *name = talloc_get_name(ptr);
1124        FILE *f = (FILE *)_f;
1125
1126        if (is_ref) {
1127                fprintf(f, "%*sreference to: %s\n", depth*4, "", name);
1128                return;
1129        }
1130
1131        if (depth == 0) {
1132                fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n", 
1133                        (max_depth < 0 ? "full " :""), name,
1134                        (unsigned long)talloc_total_size(ptr),
1135                        (unsigned long)talloc_total_blocks(ptr));
1136                return;
1137        }
1138
1139        fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n", 
1140                depth*4, "",
1141                name,
1142                (unsigned long)talloc_total_size(ptr),
1143                (unsigned long)talloc_total_blocks(ptr),
1144                (int)talloc_reference_count(ptr), ptr);
1145
1146#if 0
1147        fprintf(f, "content: ");
1148        if (talloc_total_size(ptr)) {
1149                int tot = talloc_total_size(ptr);
1150                int i;
1151
1152                for (i = 0; i < tot; i++) {
1153                        if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126)) {
1154                                fprintf(f, "%c", ((char *)ptr)[i]);
1155                        } else {
1156                                fprintf(f, "~%02x", ((char *)ptr)[i]);
1157                        }
1158                }
1159        }
1160        fprintf(f, "\n");
1161#endif
1162}
1163
1164/*
1165  report on memory usage by all children of a pointer, giving a full tree view
1166*/
1167void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f)
1168{
1169        talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_depth_FILE_helper, f);
1170        fflush(f);
1171}
1172
1173/*
1174  report on memory usage by all children of a pointer, giving a full tree view
1175*/
1176void talloc_report_full(const void *ptr, FILE *f)
1177{
1178        talloc_report_depth_file(ptr, 0, -1, f);
1179}
1180
1181/*
1182  report on memory usage by all children of a pointer
1183*/
1184void talloc_report(const void *ptr, FILE *f)
1185{
1186        talloc_report_depth_file(ptr, 0, 1, f);
1187}
1188
1189/*
1190  report on any memory hanging off the null context
1191*/
1192static void talloc_report_null(void)
1193{
1194        if (talloc_total_size(null_context) != 0) {
1195                talloc_report(null_context, stderr);
1196        }
1197}
1198
1199/*
1200  report on any memory hanging off the null context
1201*/
1202static void talloc_report_null_full(void)
1203{
1204        if (talloc_total_size(null_context) != 0) {
1205                talloc_report_full(null_context, stderr);
1206        }
1207}
1208
1209/*
1210  enable tracking of the NULL context
1211*/
1212void talloc_enable_null_tracking(void)
1213{
1214        if (null_context == NULL) {
1215                null_context = _talloc_named_const(NULL, 0, "null_context");
1216        }
1217}
1218
1219/*
1220  disable tracking of the NULL context
1221*/
1222void talloc_disable_null_tracking(void)
1223{
1224        _talloc_free(null_context);
1225        null_context = NULL;
1226}
1227
1228/*
1229  enable leak reporting on exit
1230*/
1231void talloc_enable_leak_report(void)
1232{
1233        talloc_enable_null_tracking();
1234        atexit(talloc_report_null);
1235}
1236
1237/*
1238  enable full leak reporting on exit
1239*/
1240void talloc_enable_leak_report_full(void)
1241{
1242        talloc_enable_null_tracking();
1243        atexit(talloc_report_null_full);
1244}
1245
1246/*
1247   talloc and zero memory.
1248*/
1249void *_talloc_zero(const void *ctx, size_t size, const char *name)
1250{
1251        void *p = _talloc_named_const(ctx, size, name);
1252
1253        if (p) {
1254                memset(p, '\0', size);
1255        }
1256
1257        return p;
1258}
1259
1260/*
1261  memdup with a talloc.
1262*/
1263void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name)
1264{
1265        void *newp = _talloc_named_const(t, size, name);
1266
1267        if (likely(newp)) {
1268                memcpy(newp, p, size);
1269        }
1270
1271        return newp;
1272}
1273
1274static inline char *__talloc_strlendup(const void *t, const char *p, size_t len)
1275{
1276        char *ret;
1277
1278        ret = (char *)__talloc(t, len + 1);
1279        if (unlikely(!ret)) return NULL;
1280
1281        memcpy(ret, p, len);
1282        ret[len] = 0;
1283
1284        _talloc_set_name_const(ret, ret);
1285        return ret;
1286}
1287
1288/*
1289  strdup with a talloc
1290*/
1291char *talloc_strdup(const void *t, const char *p)
1292{
1293        if (unlikely(!p)) return NULL;
1294        return __talloc_strlendup(t, p, strlen(p));
1295}
1296
1297/*
1298  strndup with a talloc
1299*/
1300char *talloc_strndup(const void *t, const char *p, size_t n)
1301{
1302        if (unlikely(!p)) return NULL;
1303        return __talloc_strlendup(t, p, n);
1304}
1305
1306static inline char *__talloc_strlendup_append(char *s, size_t slen,
1307                                              const char *a, size_t alen)
1308{
1309        char *ret;
1310
1311        ret = talloc_realloc(NULL, s, char, slen + alen + 1);
1312        if (unlikely(!ret)) return NULL;
1313
1314        /* append the string and the trailing \0 */
1315        memcpy(&ret[slen], a, alen);
1316        ret[slen+alen] = 0;
1317
1318        _talloc_set_name_const(ret, ret);
1319        return ret;
1320}
1321
1322/*
1323 * Appends at the end of the string.
1324 */
1325char *talloc_strdup_append(char *s, const char *a)
1326{
1327        if (unlikely(!s)) {
1328                return talloc_strdup(NULL, a);
1329        }
1330
1331        if (unlikely(!a)) {
1332                return s;
1333        }
1334
1335        return __talloc_strlendup_append(s, strlen(s), a, strlen(a));
1336}
1337
1338/*
1339 * Appends at the end of the talloc'ed buffer,
1340 * not the end of the string.
1341 */
1342char *talloc_strdup_append_buffer(char *s, const char *a)
1343{
1344        size_t slen;
1345
1346        if (unlikely(!s)) {
1347                return talloc_strdup(NULL, a);
1348        }
1349
1350        if (unlikely(!a)) {
1351                return s;
1352        }
1353
1354        slen = talloc_get_size(s);
1355        if (likely(slen > 0)) {
1356                slen--;
1357        }
1358
1359        return __talloc_strlendup_append(s, slen, a, strlen(a));
1360}
1361
1362/*
1363 * Appends at the end of the string.
1364 */
1365char *talloc_strndup_append(char *s, const char *a, size_t n)
1366{
1367        if (unlikely(!s)) {
1368                return talloc_strdup(NULL, a);
1369        }
1370
1371        if (unlikely(!a)) {
1372                return s;
1373        }
1374
1375        return __talloc_strlendup_append(s, strlen(s), a, n);
1376}
1377
1378/*
1379 * Appends at the end of the talloc'ed buffer,
1380 * not the end of the string.
1381 */
1382char *talloc_strndup_append_buffer(char *s, const char *a, size_t n)
1383{
1384        size_t slen;
1385
1386        if (unlikely(!s)) {
1387                return talloc_strdup(NULL, a);
1388        }
1389
1390        if (unlikely(!a)) {
1391                return s;
1392        }
1393
1394        slen = talloc_get_size(s);
1395        if (likely(slen > 0)) {
1396                slen--;
1397        }
1398
1399        return __talloc_strlendup_append(s, slen, a, n);
1400}
1401
1402
1403char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
1404{
1405        int len;
1406        char *ret;
1407        va_list ap2;
1408        char c;
1409
1410        /* this call looks strange, but it makes it work on older solaris boxes */
1411        va_copy(ap2, ap);
1412        len = vsnprintf(&c, 1, fmt, ap2);
1413        va_end(ap2);
1414        if (unlikely(len < 0)) {
1415                return NULL;
1416        }
1417
1418        ret = (char *)__talloc(t, len+1);
1419        if (unlikely(!ret)) return NULL;
1420
1421        va_copy(ap2, ap);
1422        vsnprintf(ret, len+1, fmt, ap2);
1423        va_end(ap2);
1424
1425        _talloc_set_name_const(ret, ret);
1426        return ret;
1427}
1428
1429
1430/*
1431  Perform string formatting, and return a pointer to newly allocated
1432  memory holding the result, inside a memory pool.
1433 */
1434char *talloc_asprintf(const void *t, const char *fmt, ...)
1435{
1436        va_list ap;
1437        char *ret;
1438
1439        va_start(ap, fmt);
1440        ret = talloc_vasprintf(t, fmt, ap);
1441        va_end(ap);
1442        return ret;
1443}
1444
1445static inline char *__talloc_vaslenprintf_append(char *s, size_t slen,
1446                                                 const char *fmt, va_list ap)
1447                                                 PRINTF_ATTRIBUTE(3,0);
1448
1449static inline char *__talloc_vaslenprintf_append(char *s, size_t slen,
1450                                                 const char *fmt, va_list ap)
1451{
1452        ssize_t alen;
1453        va_list ap2;
1454        char c;
1455
1456        va_copy(ap2, ap);
1457        alen = vsnprintf(&c, 1, fmt, ap2);
1458        va_end(ap2);
1459
1460        if (alen <= 0) {
1461                /* Either the vsnprintf failed or the format resulted in
1462                 * no characters being formatted. In the former case, we
1463                 * ought to return NULL, in the latter we ought to return
1464                 * the original string. Most current callers of this
1465                 * function expect it to never return NULL.
1466                 */
1467                return s;
1468        }
1469
1470        s = talloc_realloc(NULL, s, char, slen + alen + 1);
1471        if (!s) return NULL;
1472
1473        va_copy(ap2, ap);
1474        vsnprintf(s + slen, alen + 1, fmt, ap2);
1475        va_end(ap2);
1476
1477        _talloc_set_name_const(s, s);
1478        return s;
1479}
1480
1481/**
1482 * Realloc @p s to append the formatted result of @p fmt and @p ap,
1483 * and return @p s, which may have moved.  Good for gradually
1484 * accumulating output into a string buffer. Appends at the end
1485 * of the string.
1486 **/
1487char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
1488{
1489        if (unlikely(!s)) {
1490                return talloc_vasprintf(NULL, fmt, ap);
1491        }
1492
1493        return __talloc_vaslenprintf_append(s, strlen(s), fmt, ap);
1494}
1495
1496/**
1497 * Realloc @p s to append the formatted result of @p fmt and @p ap,
1498 * and return @p s, which may have moved. Always appends at the
1499 * end of the talloc'ed buffer, not the end of the string.
1500 **/
1501char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap)
1502{
1503        size_t slen;
1504
1505        if (unlikely(!s)) {
1506                return talloc_vasprintf(NULL, fmt, ap);
1507        }
1508
1509        slen = talloc_get_size(s);
1510        if (likely(slen > 0)) {
1511                slen--;
1512        }
1513
1514        return __talloc_vaslenprintf_append(s, slen, fmt, ap);
1515}
1516
1517/*
1518  Realloc @p s to append the formatted result of @p fmt and return @p
1519  s, which may have moved.  Good for gradually accumulating output
1520  into a string buffer.
1521 */
1522char *talloc_asprintf_append(char *s, const char *fmt, ...)
1523{
1524        va_list ap;
1525
1526        va_start(ap, fmt);
1527        s = talloc_vasprintf_append(s, fmt, ap);
1528        va_end(ap);
1529        return s;
1530}
1531
1532/*
1533  Realloc @p s to append the formatted result of @p fmt and return @p
1534  s, which may have moved.  Good for gradually accumulating output
1535  into a buffer.
1536 */
1537char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...)
1538{
1539        va_list ap;
1540
1541        va_start(ap, fmt);
1542        s = talloc_vasprintf_append_buffer(s, fmt, ap);
1543        va_end(ap);
1544        return s;
1545}
1546
1547/*
1548  alloc an array, checking for integer overflow in the array size
1549*/
1550void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
1551{
1552        if (count >= MAX_TALLOC_SIZE/el_size) {
1553                return NULL;
1554        }
1555        return _talloc_named_const(ctx, el_size * count, name);
1556}
1557
1558/*
1559  alloc an zero array, checking for integer overflow in the array size
1560*/
1561void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name)
1562{
1563        if (count >= MAX_TALLOC_SIZE/el_size) {
1564                return NULL;
1565        }
1566        return _talloc_zero(ctx, el_size * count, name);
1567}
1568
1569/*
1570  realloc an array, checking for integer overflow in the array size
1571*/
1572void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
1573{
1574        if (count >= MAX_TALLOC_SIZE/el_size) {
1575                return NULL;
1576        }
1577        return _talloc_realloc(ctx, ptr, el_size * count, name);
1578}
1579
1580/*
1581  a function version of talloc_realloc(), so it can be passed as a function pointer
1582  to libraries that want a realloc function (a realloc function encapsulates
1583  all the basic capabilities of an allocation library, which is why this is useful)
1584*/
1585void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
1586{
1587        return _talloc_realloc(context, ptr, size, NULL);
1588}
1589
1590
1591static int talloc_autofree_destructor(void *ptr)
1592{
1593        autofree_context = NULL;
1594        return 0;
1595}
1596
1597static void talloc_autofree(void)
1598{
1599        _talloc_free(autofree_context);
1600}
1601
1602/*
1603  return a context which will be auto-freed on exit
1604  this is useful for reducing the noise in leak reports
1605*/
1606void *talloc_autofree_context(void)
1607{
1608        if (autofree_context == NULL) {
1609                autofree_context = _talloc_named_const(NULL, 0, "autofree_context");
1610                talloc_set_destructor(autofree_context, talloc_autofree_destructor);
1611                atexit(talloc_autofree);
1612        }
1613        return autofree_context;
1614}
1615
1616size_t talloc_get_size(const void *context)
1617{
1618        struct talloc_chunk *tc;
1619
1620        if (context == NULL)
1621                return 0;
1622
1623        tc = talloc_chunk_from_ptr(context);
1624
1625        return tc->size;
1626}
1627
1628/*
1629  find a parent of this context that has the given name, if any
1630*/
1631void *talloc_find_parent_byname(const void *context, const char *name)
1632{
1633        struct talloc_chunk *tc;
1634
1635        if (context == NULL) {
1636                return NULL;
1637        }
1638
1639        tc = talloc_chunk_from_ptr(context);
1640        while (tc) {
1641                if (tc->name && strcmp(tc->name, name) == 0) {
1642                        return TC_PTR_FROM_CHUNK(tc);
1643                }
1644                while (tc && tc->prev) tc = tc->prev;
1645                if (tc) {
1646                        tc = tc->parent;
1647                }
1648        }
1649        return NULL;
1650}
1651
1652/*
1653  show the parentage of a context
1654*/
1655void talloc_show_parents(const void *context, FILE *file)
1656{
1657        struct talloc_chunk *tc;
1658
1659        if (context == NULL) {
1660                fprintf(file, "talloc no parents for NULL\n");
1661                return;
1662        }
1663
1664        tc = talloc_chunk_from_ptr(context);
1665        fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
1666        while (tc) {
1667                fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)));
1668                while (tc && tc->prev) tc = tc->prev;
1669                if (tc) {
1670                        tc = tc->parent;
1671                }
1672        }
1673        fflush(file);
1674}
1675
1676/*
1677  return 1 if ptr is a parent of context
1678*/
1679int talloc_is_parent(const void *context, const void *ptr)
1680{
1681        struct talloc_chunk *tc;
1682
1683        if (context == NULL) {
1684                return 0;
1685        }
1686
1687        tc = talloc_chunk_from_ptr(context);
1688        while (tc) {
1689                if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1;
1690                while (tc && tc->prev) tc = tc->prev;
1691                if (tc) {
1692                        tc = tc->parent;
1693                }
1694        }
1695        return 0;
1696}
Note: See TracBrowser for help on using the repository browser.