ia64/xen-unstable

view tools/xenstore/talloc.c @ 19731:01748ccc4da3

Intel VT-d: fix Stoakley boot issue with iommu=1

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