source: releases/0.11.0/lib/talloc.c@ 293

Last change on this file since 293 was 147, checked in by tim, 16 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
Line 
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.