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,const void * ptr)322 int talloc_unlink(const void *context, const 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(const void * ptr)502 static void talloc_free_children(const 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(const void * ptr)542 int talloc_free(const void *ptr)
543 {
544 	int saved_errno = errno;
545 	struct talloc_chunk *tc;
546 
547 	if (ptr == NULL) {
548 		goto err;
549 	}
550 
551 	tc = talloc_chunk_from_ptr(ptr);
552 
553 	if (tc->null_refs) {
554 		tc->null_refs--;
555 		goto err;
556 	}
557 
558 	if (tc->refs) {
559 		talloc_reference_destructor(tc->refs);
560 		goto err;
561 	}
562 
563 	if (tc->flags & TALLOC_FLAG_LOOP) {
564 		/* we have a free loop - stop looping */
565 		goto success;
566 	}
567 
568 	if (tc->destructor) {
569 		talloc_destructor_t d = tc->destructor;
570 		if (d == (talloc_destructor_t)-1) {
571 			goto err;
572 		}
573 		tc->destructor = (talloc_destructor_t)-1;
574 
575 		/* The destructor needs to be able to change the object! */
576 		if (d((void *)ptr) == -1) {
577 			tc->destructor = d;
578 			goto err;
579 		}
580 		tc->destructor = NULL;
581 	}
582 
583 	tc->flags |= TALLOC_FLAG_LOOP;
584 
585 	talloc_free_children(ptr);
586 
587 	if (tc->parent) {
588 		_TLIST_REMOVE(tc->parent->child, tc);
589 		if (tc->parent->child) {
590 			tc->parent->child->parent = tc->parent;
591 		}
592 	} else {
593 		if (tc->prev) tc->prev->next = tc->next;
594 		if (tc->next) tc->next->prev = tc->prev;
595 	}
596 
597 	tc->flags |= TALLOC_FLAG_FREE;
598 
599 	free(tc);
600  success:
601 	errno = saved_errno;
602 	return 0;
603 
604  err:
605 	errno = saved_errno;
606 	return -1;
607 }
608 
609 /*
610   A talloc version of realloc. The context argument is only used if
611   ptr is NULL
612 */
_talloc_realloc(const void * context,void * ptr,size_t size,const char * name)613 void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name)
614 {
615 	struct talloc_chunk *tc;
616 	void *new_ptr;
617 
618 	/* size zero is equivalent to free() */
619 	if (size == 0) {
620 		talloc_free(ptr);
621 		return NULL;
622 	}
623 
624 	if (size >= MAX_TALLOC_SIZE) {
625 		return NULL;
626 	}
627 
628 	/* realloc(NULL) is equavalent to malloc() */
629 	if (ptr == NULL) {
630 		return talloc_named_const(context, size, name);
631 	}
632 
633 	tc = talloc_chunk_from_ptr(ptr);
634 
635 	/* don't allow realloc on referenced pointers */
636 	if (tc->refs) {
637 		return NULL;
638 	}
639 
640 	/* by resetting magic we catch users of the old memory */
641 	tc->flags |= TALLOC_FLAG_FREE;
642 
643 #if ALWAYS_REALLOC
644 	new_ptr = malloc(size + TC_HDR_SIZE);
645 	if (new_ptr) {
646 		memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE);
647 		free(tc);
648 	}
649 #else
650 	new_ptr = realloc(tc, size + TC_HDR_SIZE);
651 #endif
652 	if (!new_ptr) {
653 		tc->flags &= ~TALLOC_FLAG_FREE;
654 		return NULL;
655 	}
656 
657 	tc = new_ptr;
658 	tc->flags &= ~TALLOC_FLAG_FREE;
659 	if (tc->parent) {
660 		tc->parent->child = new_ptr;
661 	}
662 	if (tc->child) {
663 		tc->child->parent = new_ptr;
664 	}
665 
666 	if (tc->prev) {
667 		tc->prev->next = tc;
668 	}
669 	if (tc->next) {
670 		tc->next->prev = tc;
671 	}
672 
673 	tc->size = size;
674 	talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
675 
676 	return TC_PTR_FROM_CHUNK(tc);
677 }
678 
679 /*
680    move a lump of memory from one talloc context to another return the
681    ptr on success, or NULL if it could not be transferred.
682    passing NULL as ptr will always return NULL with no side effects.
683 */
talloc_steal(const void * new_ctx,const void * ptr)684 void *talloc_steal(const void *new_ctx, const void *ptr)
685 {
686 	struct talloc_chunk *tc, *new_tc;
687 
688 	if (!ptr) {
689 		return NULL;
690 	}
691 
692 	if (new_ctx == NULL) {
693 		new_ctx = null_context;
694 	}
695 
696 	tc = talloc_chunk_from_ptr(ptr);
697 
698 	if (new_ctx == NULL) {
699 		if (tc->parent) {
700 			_TLIST_REMOVE(tc->parent->child, tc);
701 			if (tc->parent->child) {
702 				tc->parent->child->parent = tc->parent;
703 			}
704 		} else {
705 			if (tc->prev) tc->prev->next = tc->next;
706 			if (tc->next) tc->next->prev = tc->prev;
707 		}
708 
709 		tc->parent = tc->next = tc->prev = NULL;
710 		return discard_const_p(void, ptr);
711 	}
712 
713 	new_tc = talloc_chunk_from_ptr(new_ctx);
714 
715 	if (tc == new_tc) {
716 		return discard_const_p(void, ptr);
717 	}
718 
719 	if (tc->parent) {
720 		_TLIST_REMOVE(tc->parent->child, tc);
721 		if (tc->parent->child) {
722 			tc->parent->child->parent = tc->parent;
723 		}
724 	} else {
725 		if (tc->prev) tc->prev->next = tc->next;
726 		if (tc->next) tc->next->prev = tc->prev;
727 	}
728 
729 	tc->parent = new_tc;
730 	if (new_tc->child) new_tc->child->parent = NULL;
731 	_TLIST_ADD(new_tc->child, tc);
732 
733 	return discard_const_p(void, ptr);
734 }
735 
736 /*
737   return the total size of a talloc pool (subtree)
738 */
talloc_total_size(const void * ptr)739 off_t talloc_total_size(const void *ptr)
740 {
741 	off_t total = 0;
742 	struct talloc_chunk *c, *tc;
743 
744 	if (ptr == NULL) {
745 		ptr = null_context;
746 	}
747 	if (ptr == NULL) {
748 		return 0;
749 	}
750 
751 	tc = talloc_chunk_from_ptr(ptr);
752 
753 	if (tc->flags & TALLOC_FLAG_LOOP) {
754 		return 0;
755 	}
756 
757 	tc->flags |= TALLOC_FLAG_LOOP;
758 
759 	total = tc->size;
760 	for (c=tc->child;c;c=c->next) {
761 		total += talloc_total_size(TC_PTR_FROM_CHUNK(c));
762 	}
763 
764 	tc->flags &= ~TALLOC_FLAG_LOOP;
765 
766 	return total;
767 }
768 
769 /*
770   return the total number of blocks in a talloc pool (subtree)
771 */
talloc_total_blocks(const void * ptr)772 off_t talloc_total_blocks(const void *ptr)
773 {
774 	off_t total = 0;
775 	struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
776 
777 	if (tc->flags & TALLOC_FLAG_LOOP) {
778 		return 0;
779 	}
780 
781 	tc->flags |= TALLOC_FLAG_LOOP;
782 
783 	total++;
784 	for (c=tc->child;c;c=c->next) {
785 		total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c));
786 	}
787 
788 	tc->flags &= ~TALLOC_FLAG_LOOP;
789 
790 	return total;
791 }
792 
793 /*
794   return the number of external references to a pointer
795 */
talloc_reference_count(const void * ptr)796 static int talloc_reference_count(const void *ptr)
797 {
798 	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
799 	struct talloc_reference_handle *h;
800 	int ret = 0;
801 
802 	for (h=tc->refs;h;h=h->next) {
803 		ret++;
804 	}
805 	return ret;
806 }
807 
808 /*
809   report on memory usage by all children of a pointer, giving a full tree view
810 */
talloc_report_depth(const void * ptr,FILE * f,int depth)811 void talloc_report_depth(const void *ptr, FILE *f, int depth)
812 {
813 	struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
814 
815 	if (tc->flags & TALLOC_FLAG_LOOP) {
816 		return;
817 	}
818 
819 	tc->flags |= TALLOC_FLAG_LOOP;
820 
821 	for (c=tc->child;c;c=c->next) {
822 		if (c->name == TALLOC_MAGIC_REFERENCE) {
823 			struct talloc_reference_handle *handle = TC_PTR_FROM_CHUNK(c);
824 			const char *name2 = talloc_get_name(handle->ptr);
825 			fprintf(f, "%*sreference to: %s\n", depth*4, "", name2);
826 		} else {
827 			const char *name = talloc_get_name(TC_PTR_FROM_CHUNK(c));
828 			fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n",
829 				depth*4, "",
830 				name,
831 				(unsigned long)talloc_total_size(TC_PTR_FROM_CHUNK(c)),
832 				(unsigned long)talloc_total_blocks(TC_PTR_FROM_CHUNK(c)),
833 				talloc_reference_count(TC_PTR_FROM_CHUNK(c)));
834 			talloc_report_depth(TC_PTR_FROM_CHUNK(c), f, depth+1);
835 		}
836 	}
837 	tc->flags &= ~TALLOC_FLAG_LOOP;
838 }
839 
840 /*
841   report on memory usage by all children of a pointer, giving a full tree view
842 */
talloc_report_full(const void * ptr,FILE * f)843 void talloc_report_full(const void *ptr, FILE *f)
844 {
845 	if (ptr == NULL) {
846 		ptr = null_context;
847 	}
848 	if (ptr == NULL) return;
849 
850 	fprintf(f,"full talloc report on '%s' (total %lu bytes in %lu blocks)\n",
851 		talloc_get_name(ptr),
852 		(unsigned long)talloc_total_size(ptr),
853 		(unsigned long)talloc_total_blocks(ptr));
854 
855 	talloc_report_depth(ptr, f, 1);
856 	fflush(f);
857 }
858 
859 /*
860   report on memory usage by all children of a pointer
861 */
talloc_report(const void * ptr,FILE * f)862 void talloc_report(const void *ptr, FILE *f)
863 {
864 	struct talloc_chunk *c, *tc;
865 
866 	if (ptr == NULL) {
867 		ptr = null_context;
868 	}
869 	if (ptr == NULL) return;
870 
871 	fprintf(f,"talloc report on '%s' (total %lu bytes in %lu blocks)\n",
872 		talloc_get_name(ptr),
873 		(unsigned long)talloc_total_size(ptr),
874 		(unsigned long)talloc_total_blocks(ptr));
875 
876 	tc = talloc_chunk_from_ptr(ptr);
877 
878 	for (c=tc->child;c;c=c->next) {
879 		fprintf(f, "\t%-30s contains %6lu bytes in %3lu blocks\n",
880 			talloc_get_name(TC_PTR_FROM_CHUNK(c)),
881 			(unsigned long)talloc_total_size(TC_PTR_FROM_CHUNK(c)),
882 			(unsigned long)talloc_total_blocks(TC_PTR_FROM_CHUNK(c)));
883 	}
884 	fflush(f);
885 }
886 
887 /*
888   report on any memory hanging off the null context
889 */
talloc_report_null(void)890 static void talloc_report_null(void)
891 {
892 	if (talloc_total_size(null_context) != 0) {
893 		talloc_report(null_context, stderr);
894 	}
895 }
896 
897 /*
898   report on any memory hanging off the null context
899 */
talloc_report_null_full(void)900 static void talloc_report_null_full(void)
901 {
902 	if (talloc_total_size(null_context) != 0) {
903 		talloc_report_full(null_context, stderr);
904 	}
905 }
906 
907 /*
908   enable tracking of the NULL context
909 */
talloc_enable_null_tracking(void)910 void talloc_enable_null_tracking(void)
911 {
912 	if (null_context == NULL) {
913 		null_context = talloc_named_const(NULL, 0, "null_context");
914 	}
915 }
916 
917 #ifdef _SAMBA_BUILD_
918 /* Ugly calls to Samba-specific sprintf_append... JRA. */
919 
920 /*
921   report on memory usage by all children of a pointer, giving a full tree view
922 */
talloc_report_depth_str(const void * ptr,char ** pps,ssize_t * plen,size_t * pbuflen,int depth)923 static void talloc_report_depth_str(const void *ptr, char **pps, ssize_t *plen, size_t *pbuflen, int depth)
924 {
925 	struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
926 
927 	if (tc->flags & TALLOC_FLAG_LOOP) {
928 		return;
929 	}
930 
931 	tc->flags |= TALLOC_FLAG_LOOP;
932 
933 	for (c=tc->child;c;c=c->next) {
934 		if (c->name == TALLOC_MAGIC_REFERENCE) {
935 			struct talloc_reference_handle *handle = TC_PTR_FROM_CHUNK(c);
936 			const char *name2 = talloc_get_name(handle->ptr);
937 
938 			sprintf_append(NULL, pps, plen, pbuflen,
939 				"%*sreference to: %s\n", depth*4, "", name2);
940 
941 		} else {
942 			const char *name = talloc_get_name(TC_PTR_FROM_CHUNK(c));
943 
944 			sprintf_append(NULL, pps, plen, pbuflen,
945 				"%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n",
946 				depth*4, "",
947 				name,
948 				(unsigned long)talloc_total_size(TC_PTR_FROM_CHUNK(c)),
949 				(unsigned long)talloc_total_blocks(TC_PTR_FROM_CHUNK(c)),
950 				talloc_reference_count(TC_PTR_FROM_CHUNK(c)));
951 
952 			talloc_report_depth_str(TC_PTR_FROM_CHUNK(c), pps, plen, pbuflen, depth+1);
953 		}
954 	}
955 	tc->flags &= ~TALLOC_FLAG_LOOP;
956 }
957 
958 /*
959   report on memory usage by all children of a pointer
960 */
talloc_describe_all(void)961 char *talloc_describe_all(void)
962 {
963 	ssize_t len = 0;
964 	size_t buflen = 512;
965 	char *s = NULL;
966 
967 	if (null_context == NULL) {
968 		return NULL;
969 	}
970 
971 	sprintf_append(NULL, &s, &len, &buflen,
972 		"full talloc report on '%s' (total %lu bytes in %lu blocks)\n",
973 		talloc_get_name(null_context),
974 		(unsigned long)talloc_total_size(null_context),
975 		(unsigned long)talloc_total_blocks(null_context));
976 
977 	if (!s) {
978 		return NULL;
979 	}
980 	talloc_report_depth_str(null_context, &s, &len, &buflen, 1);
981 	return s;
982 }
983 #endif
984 
985 /*
986   enable leak reporting on exit
987 */
talloc_enable_leak_report(void)988 void talloc_enable_leak_report(void)
989 {
990 	talloc_enable_null_tracking();
991 	atexit(talloc_report_null);
992 }
993 
994 /*
995   enable full leak reporting on exit
996 */
talloc_enable_leak_report_full(void)997 void talloc_enable_leak_report_full(void)
998 {
999 	talloc_enable_null_tracking();
1000 	atexit(talloc_report_null_full);
1001 }
1002 
1003 /*
1004    talloc and zero memory.
1005 */
_talloc_zero(const void * ctx,size_t size,const char * name)1006 void *_talloc_zero(const void *ctx, size_t size, const char *name)
1007 {
1008 	void *p = talloc_named_const(ctx, size, name);
1009 
1010 	if (p) {
1011 		memset(p, '\0', size);
1012 	}
1013 
1014 	return p;
1015 }
1016 
1017 
1018 /*
1019   memdup with a talloc.
1020 */
_talloc_memdup(const void * t,const void * p,size_t size,const char * name)1021 void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name)
1022 {
1023 	void *newp = talloc_named_const(t, size, name);
1024 
1025 	if (newp) {
1026 		memcpy(newp, p, size);
1027 	}
1028 
1029 	return newp;
1030 }
1031 
1032 /*
1033   strdup with a talloc
1034 */
talloc_strdup(const void * t,const char * p)1035 char *talloc_strdup(const void *t, const char *p)
1036 {
1037 	char *ret;
1038 	if (!p) {
1039 		return NULL;
1040 	}
1041 	ret = talloc_memdup(t, p, strlen(p) + 1);
1042 	if (ret) {
1043 		talloc_set_name_const(ret, ret);
1044 	}
1045 	return ret;
1046 }
1047 
1048 /*
1049  append to a talloced string
1050 */
talloc_append_string(const void * t,char * orig,const char * append)1051 char *talloc_append_string(const void *t, char *orig, const char *append)
1052 {
1053 	char *ret;
1054 	size_t olen = strlen(orig);
1055 	size_t alenz;
1056 
1057 	if (!append)
1058 		return orig;
1059 
1060 	alenz = strlen(append) + 1;
1061 
1062 	ret = talloc_realloc(t, orig, char, olen + alenz);
1063 	if (!ret)
1064 		return NULL;
1065 
1066 	/* append the string with the trailing \0 */
1067 	memcpy(&ret[olen], append, alenz);
1068 
1069 	return ret;
1070 }
1071 
1072 /*
1073   strndup with a talloc
1074 */
talloc_strndup(const void * t,const char * p,size_t n)1075 char *talloc_strndup(const void *t, const char *p, size_t n)
1076 {
1077 	size_t len;
1078 	char *ret;
1079 
1080 	for (len=0; len<n && p[len]; len++) ;
1081 
1082 	ret = _talloc(t, len + 1);
1083 	if (!ret) { return NULL; }
1084 	memcpy(ret, p, len);
1085 	ret[len] = 0;
1086 	talloc_set_name_const(ret, ret);
1087 	return ret;
1088 }
1089 
1090 #ifndef VA_COPY
1091 #ifdef HAVE_VA_COPY
1092 #define VA_COPY(dest, src) va_copy(dest, src)
1093 #elif defined(HAVE___VA_COPY)
1094 #define VA_COPY(dest, src) __va_copy(dest, src)
1095 #else
1096 #define VA_COPY(dest, src) (dest) = (src)
1097 #endif
1098 #endif
1099 
talloc_vasprintf(const void * t,const char * fmt,va_list ap)1100 char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
1101 {
1102 	int len;
1103 	char *ret;
1104 	va_list ap2;
1105 	char c;
1106 
1107 	VA_COPY(ap2, ap);
1108 
1109 	/* this call looks strange, but it makes it work on older solaris boxes */
1110 	if ((len = vsnprintf(&c, 1, fmt, ap2)) < 0) {
1111 		va_end(ap2);
1112 		return NULL;
1113 	}
1114 	va_end(ap2);
1115 
1116 	ret = _talloc(t, len+1);
1117 	if (ret) {
1118 		VA_COPY(ap2, ap);
1119 		vsnprintf(ret, len+1, fmt, ap2);
1120 		va_end(ap2);
1121 		talloc_set_name_const(ret, ret);
1122 	}
1123 
1124 	return ret;
1125 }
1126 
1127 
1128 /*
1129   Perform string formatting, and return a pointer to newly allocated
1130   memory holding the result, inside a memory pool.
1131  */
talloc_asprintf(const void * t,const char * fmt,...)1132 char *talloc_asprintf(const void *t, const char *fmt, ...)
1133 {
1134 	va_list ap;
1135 	char *ret;
1136 
1137 	va_start(ap, fmt);
1138 	ret = talloc_vasprintf(t, fmt, ap);
1139 	va_end(ap);
1140 	return ret;
1141 }
1142 
1143 
1144 /**
1145  * Realloc @p s to append the formatted result of @p fmt and @p ap,
1146  * and return @p s, which may have moved.  Good for gradually
1147  * accumulating output into a string buffer.
1148  **/
1149 
1150 static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
1151 
talloc_vasprintf_append(char * s,const char * fmt,va_list ap)1152 static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
1153 {
1154 	struct talloc_chunk *tc;
1155 	int len, s_len;
1156 	va_list ap2;
1157 
1158 	if (s == NULL) {
1159 		return talloc_vasprintf(NULL, fmt, ap);
1160 	}
1161 
1162 	tc = talloc_chunk_from_ptr(s);
1163 
1164 	VA_COPY(ap2, ap);
1165 
1166 	s_len = tc->size - 1;
1167 	if ((len = vsnprintf(NULL, 0, fmt, ap2)) <= 0) {
1168 		/* Either the vsnprintf failed or the format resulted in
1169 		 * no characters being formatted. In the former case, we
1170 		 * ought to return NULL, in the latter we ought to return
1171 		 * the original string. Most current callers of this
1172 		 * function expect it to never return NULL.
1173 		 */
1174 		va_end(ap2);
1175 		return s;
1176 	}
1177 	va_end(ap2);
1178 
1179 	s = talloc_realloc(NULL, s, char, s_len + len+1);
1180 	if (!s) return NULL;
1181 
1182 	VA_COPY(ap2, ap);
1183 
1184 	vsnprintf(s+s_len, len+1, fmt, ap2);
1185 	va_end(ap2);
1186 	talloc_set_name_const(s, s);
1187 
1188 	return s;
1189 }
1190 
1191 /*
1192   Realloc @p s to append the formatted result of @p fmt and return @p
1193   s, which may have moved.  Good for gradually accumulating output
1194   into a string buffer.
1195  */
talloc_asprintf_append(char * s,const char * fmt,...)1196 char *talloc_asprintf_append(char *s, const char *fmt, ...)
1197 {
1198 	va_list ap;
1199 
1200 	va_start(ap, fmt);
1201 	s = talloc_vasprintf_append(s, fmt, ap);
1202 	va_end(ap);
1203 	return s;
1204 }
1205 
1206 /*
1207   alloc an array, checking for integer overflow in the array size
1208 */
_talloc_array(const void * ctx,size_t el_size,unsigned count,const char * name)1209 void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
1210 {
1211 	if (count >= MAX_TALLOC_SIZE/el_size) {
1212 		return NULL;
1213 	}
1214 	return talloc_named_const(ctx, el_size * count, name);
1215 }
1216 
1217 /*
1218   alloc an zero array, checking for integer overflow in the array size
1219 */
_talloc_zero_array(const void * ctx,size_t el_size,unsigned count,const char * name)1220 void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name)
1221 {
1222 	if (count >= MAX_TALLOC_SIZE/el_size) {
1223 		return NULL;
1224 	}
1225 	return _talloc_zero(ctx, el_size * count, name);
1226 }
1227 
1228 
1229 /*
1230   realloc an array, checking for integer overflow in the array size
1231 */
_talloc_realloc_array(const void * ctx,void * ptr,size_t el_size,unsigned count,const char * name)1232 void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
1233 {
1234 	if (count >= MAX_TALLOC_SIZE/el_size) {
1235 		return NULL;
1236 	}
1237 	return _talloc_realloc(ctx, ptr, el_size * count, name);
1238 }
1239 
1240 /*
1241   a function version of talloc_realloc(), so it can be passed as a function pointer
1242   to libraries that want a realloc function (a realloc function encapsulates
1243   all the basic capabilities of an allocation library, which is why this is useful)
1244 */
talloc_realloc_fn(const void * context,void * ptr,size_t size)1245 void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
1246 {
1247 	return _talloc_realloc(context, ptr, size, NULL);
1248 }
1249 
1250 
talloc_autofree(void)1251 static void talloc_autofree(void)
1252 {
1253 	talloc_free(cleanup_context);
1254 	cleanup_context = NULL;
1255 }
1256 
1257 /*
1258   return a context which will be auto-freed on exit
1259   this is useful for reducing the noise in leak reports
1260 */
talloc_autofree_context(void)1261 void *talloc_autofree_context(void)
1262 {
1263 	if (cleanup_context == NULL) {
1264 		cleanup_context = talloc_named_const(NULL, 0, "autofree_context");
1265 		atexit(talloc_autofree);
1266 	}
1267 	return cleanup_context;
1268 }
1269 
talloc_get_size(const void * context)1270 size_t talloc_get_size(const void *context)
1271 {
1272 	struct talloc_chunk *tc;
1273 
1274 	if (context == NULL)
1275 		return 0;
1276 
1277 	tc = talloc_chunk_from_ptr(context);
1278 
1279 	return tc->size;
1280 }
1281 
1282 /*
1283   find a parent of this context that has the given name, if any
1284 */
talloc_find_parent_byname(const void * context,const char * name)1285 void *talloc_find_parent_byname(const void *context, const char *name)
1286 {
1287 	struct talloc_chunk *tc;
1288 
1289 	if (context == NULL) {
1290 		return NULL;
1291 	}
1292 
1293 	tc = talloc_chunk_from_ptr(context);
1294 	while (tc) {
1295 		if (tc->name && strcmp(tc->name, name) == 0) {
1296 			return TC_PTR_FROM_CHUNK(tc);
1297 		}
1298 		while (tc && tc->prev) tc = tc->prev;
1299 		tc = tc->parent;
1300 	}
1301 	return NULL;
1302 }
1303 
1304 /*
1305   show the parentage of a context
1306 */
talloc_show_parents(const void * context,FILE * file)1307 void talloc_show_parents(const void *context, FILE *file)
1308 {
1309 	struct talloc_chunk *tc;
1310 
1311 	if (context == NULL) {
1312 		fprintf(file, "talloc no parents for NULL\n");
1313 		return;
1314 	}
1315 
1316 	tc = talloc_chunk_from_ptr(context);
1317 	fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
1318 	while (tc) {
1319 		fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)));
1320 		while (tc && tc->prev) tc = tc->prev;
1321 		tc = tc->parent;
1322 	}
1323 }
1324