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