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