2 Samba Unix SMB/CIFS implementation.
4 Samba trivial allocation library - new interface
6 NOTE: Please read talloc_guide.txt for full documentation
8 Copyright (C) Andrew Tridgell 2004
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 inspired by http://swapped.cc/halloc/
32 #if ((SAMBA_VERSION_MAJOR==3)&&(SAMBA_VERSION_MINOR<9))
33 /* This is to circumvent SAMBA3's paranoid malloc checker. Here in this file
34 * we trust ourselves... */
49 /* assume a modern system */
53 /* use this to force every realloc to change the pointer, to stress test
54 code that might not cope */
55 #define ALWAYS_REALLOC 0
58 #define MAX_TALLOC_SIZE 0x10000000
59 #define TALLOC_MAGIC 0xe814ec4f
60 #define TALLOC_MAGIC_FREE 0x7faebef3
61 #define TALLOC_MAGIC_REFERENCE ((const char *)1)
63 /* by default we abort when given a bad pointer (such as when talloc_free() is called
64 on a pointer that came from malloc() */
66 #define TALLOC_ABORT(reason) abort()
69 #ifndef discard_const_p
70 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
71 # define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
73 # define discard_const_p(type, ptr) ((type *)(ptr))
77 /* this null_context is only used if talloc_enable_leak_report() or
78 talloc_enable_leak_report_full() is called, otherwise it remains
81 static const void *null_context
;
82 static void *cleanup_context
;
85 struct talloc_reference_handle
{
86 struct talloc_reference_handle
*next
, *prev
;
90 typedef int (*talloc_destructor_t
)(void *);
93 struct talloc_chunk
*next
, *prev
;
94 struct talloc_chunk
*parent
, *child
;
95 struct talloc_reference_handle
*refs
;
97 talloc_destructor_t destructor
;
105 /* panic if we get a bad magic value */
106 static struct talloc_chunk
*talloc_chunk_from_ptr(const void *ptr
)
108 struct talloc_chunk
*tc
= discard_const_p(struct talloc_chunk
, ptr
)-1;
109 if (tc
->u
.magic
!= TALLOC_MAGIC
) {
110 if (tc
->u
.magic
== TALLOC_MAGIC_FREE
) {
111 TALLOC_ABORT("Bad talloc magic value - double free");
113 TALLOC_ABORT("Bad talloc magic value - unknown value");
120 /* hook into the front of the list */
121 #define _TLIST_ADD(list, p) \
125 (p)->next = (p)->prev = NULL; \
127 (list)->prev = (p); \
128 (p)->next = (list); \
134 /* remove an element from a list - element doesn't have to be in list. */
135 #define _TLIST_REMOVE(list, p) \
137 if ((p) == (list)) { \
138 (list) = (p)->next; \
139 if (list) (list)->prev = NULL; \
141 if ((p)->prev) (p)->prev->next = (p)->next; \
142 if ((p)->next) (p)->next->prev = (p)->prev; \
144 if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
149 return the parent chunk of a pointer
151 static struct talloc_chunk
*talloc_parent_chunk(const void *ptr
)
153 struct talloc_chunk
*tc
= talloc_chunk_from_ptr(ptr
);
154 while (tc
->prev
) tc
=tc
->prev
;
158 void *talloc_parent(const void *ptr
)
160 struct talloc_chunk
*tc
= talloc_parent_chunk(ptr
);
161 return tc
? (void *)(tc
+1) : NULL
;
165 Allocate a bit of memory as a child of an existing pointer
167 void *_talloc(const void *context
, size_t size
)
169 struct talloc_chunk
*tc
;
171 if (context
== NULL
) {
172 context
= null_context
;
175 if (size
>= MAX_TALLOC_SIZE
) {
179 tc
= malloc(sizeof(*tc
)+size
);
180 if (tc
== NULL
) return NULL
;
183 tc
->u
.magic
= TALLOC_MAGIC
;
184 tc
->destructor
= NULL
;
190 struct talloc_chunk
*parent
= talloc_chunk_from_ptr(context
);
195 parent
->child
->parent
= NULL
;
198 _TLIST_ADD(parent
->child
, tc
);
200 tc
->next
= tc
->prev
= tc
->parent
= NULL
;
203 return (void *)(tc
+1);
208 setup a destructor to be called on free of a pointer
209 the destructor should return 0 on success, or -1 on failure.
210 if the destructor fails then the free is failed, and the memory can
211 be continued to be used
213 void talloc_set_destructor(const void *ptr
, int (*destructor
)(void *))
215 struct talloc_chunk
*tc
= talloc_chunk_from_ptr(ptr
);
216 tc
->destructor
= destructor
;
220 increase the reference count on a piece of memory.
222 void talloc_increase_ref_count(const void *ptr
)
224 talloc_reference(null_context
, ptr
);
228 helper for talloc_reference()
230 static int talloc_reference_destructor(void *ptr
)
232 struct talloc_reference_handle
*handle
= ptr
;
233 struct talloc_chunk
*tc1
= talloc_chunk_from_ptr(ptr
);
234 struct talloc_chunk
*tc2
= talloc_chunk_from_ptr(handle
->ptr
);
235 if (tc1
->destructor
!= (talloc_destructor_t
)-1) {
236 tc1
->destructor
= NULL
;
238 _TLIST_REMOVE(tc2
->refs
, handle
);
244 make a secondary reference to a pointer, hanging off the given context.
245 the pointer remains valid until both the original caller and this given
248 the major use for this is when two different structures need to reference the
249 same underlying data, and you want to be able to free the two instances separately,
252 void *talloc_reference(const void *context
, const void *ptr
)
254 struct talloc_chunk
*tc
;
255 struct talloc_reference_handle
*handle
;
256 if (ptr
== NULL
) return NULL
;
258 tc
= talloc_chunk_from_ptr(ptr
);
259 handle
= talloc_named_const(context
, sizeof(*handle
), TALLOC_MAGIC_REFERENCE
);
261 if (handle
== NULL
) return NULL
;
263 /* note that we hang the destructor off the handle, not the
264 main context as that allows the caller to still setup their
265 own destructor on the context if they want to */
266 talloc_set_destructor(handle
, talloc_reference_destructor
);
267 handle
->ptr
= discard_const_p(void, ptr
);
268 _TLIST_ADD(tc
->refs
, handle
);
273 remove a secondary reference to a pointer. This undo's what
274 talloc_reference() has done. The context and pointer arguments
275 must match those given to a talloc_reference()
277 static int talloc_unreference(const void *context
, const void *ptr
)
279 struct talloc_chunk
*tc
= talloc_chunk_from_ptr(ptr
);
280 struct talloc_reference_handle
*h
;
282 if (context
== NULL
) {
283 context
= null_context
;
286 for (h
=tc
->refs
;h
;h
=h
->next
) {
287 struct talloc_chunk
*p
= talloc_parent_chunk(h
);
288 if ((p
==NULL
&& context
==NULL
) || p
+1 == context
) break;
294 talloc_set_destructor(h
, NULL
);
295 _TLIST_REMOVE(tc
->refs
, h
);
301 remove a specific parent context from a pointer. This is a more
302 controlled varient of talloc_free()
304 int talloc_unlink(const void *context
, void *ptr
)
306 struct talloc_chunk
*tc_p
, *new_p
;
313 if (context
== NULL
) {
314 context
= null_context
;
317 if (talloc_unreference(context
, ptr
) == 0) {
321 if (context
== NULL
) {
322 if (talloc_parent_chunk(ptr
) != NULL
) {
326 if (talloc_chunk_from_ptr(context
) != talloc_parent_chunk(ptr
)) {
331 tc_p
= talloc_chunk_from_ptr(ptr
);
333 if (tc_p
->refs
== NULL
) {
334 return talloc_free(ptr
);
337 new_p
= talloc_parent_chunk(tc_p
->refs
);
339 new_parent
= new_p
+1;
344 if (talloc_unreference(new_parent
, ptr
) != 0) {
348 talloc_steal(new_parent
, ptr
);
354 add a name to an existing pointer - va_list version
356 static void talloc_set_name_v(const void *ptr
, const char *fmt
, va_list ap
) PRINTF_ATTRIBUTE(2,0);
358 static void talloc_set_name_v(const void *ptr
, const char *fmt
, va_list ap
)
360 struct talloc_chunk
*tc
= talloc_chunk_from_ptr(ptr
);
361 tc
->name
= talloc_vasprintf(ptr
, fmt
, ap
);
363 talloc_set_name_const(tc
->name
, ".name");
368 add a name to an existing pointer
370 void talloc_set_name(const void *ptr
, const char *fmt
, ...)
374 talloc_set_name_v(ptr
, fmt
, ap
);
379 more efficient way to add a name to a pointer - the name must point to a
382 void talloc_set_name_const(const void *ptr
, const char *name
)
384 struct talloc_chunk
*tc
= talloc_chunk_from_ptr(ptr
);
389 create a named talloc pointer. Any talloc pointer can be named, and
390 talloc_named() operates just like talloc() except that it allows you
393 void *talloc_named(const void *context
, size_t size
, const char *fmt
, ...)
398 ptr
= _talloc(context
, size
);
399 if (ptr
== NULL
) return NULL
;
402 talloc_set_name_v(ptr
, fmt
, ap
);
409 create a named talloc pointer. Any talloc pointer can be named, and
410 talloc_named() operates just like talloc() except that it allows you
413 void *talloc_named_const(const void *context
, size_t size
, const char *name
)
417 ptr
= _talloc(context
, size
);
422 talloc_set_name_const(ptr
, name
);
428 return the name of a talloc ptr, or "UNNAMED"
430 const char *talloc_get_name(const void *ptr
)
432 struct talloc_chunk
*tc
= talloc_chunk_from_ptr(ptr
);
433 if (tc
->name
== TALLOC_MAGIC_REFERENCE
) {
444 check if a pointer has the given name. If it does, return the pointer,
445 otherwise return NULL
447 void *talloc_check_name(const void *ptr
, const char *name
)
450 if (ptr
== NULL
) return NULL
;
451 pname
= talloc_get_name(ptr
);
452 if (pname
== name
|| strcmp(pname
, name
) == 0) {
453 return discard_const_p(void, ptr
);
460 this is for compatibility with older versions of talloc
462 void *talloc_init(const char *fmt
, ...)
467 ptr
= _talloc(NULL
, 0);
468 if (ptr
== NULL
) return NULL
;
471 talloc_set_name_v(ptr
, fmt
, ap
);
478 this is a replacement for the Samba3 talloc_destroy_pool functionality. It
479 should probably not be used in new code. It's in here to keep the talloc
480 code consistent across Samba 3 and 4.
482 void talloc_free_children(void *ptr
)
484 struct talloc_chunk
*tc
;
490 tc
= talloc_chunk_from_ptr(ptr
);
493 /* we need to work out who will own an abandoned child
494 if it cannot be freed. In priority order, the first
495 choice is owner of any remaining reference to this
496 pointer, the second choice is our parent, and the
497 final choice is the null context. */
498 void *child
= tc
->child
+1;
499 const void *new_parent
= null_context
;
500 if (tc
->child
->refs
) {
501 struct talloc_chunk
*p
= talloc_parent_chunk(tc
->child
->refs
);
502 if (p
) new_parent
= p
+1;
504 if (talloc_free(child
) == -1) {
505 if (new_parent
== null_context
) {
506 struct talloc_chunk
*p
= talloc_parent_chunk(ptr
);
507 if (p
) new_parent
= p
+1;
509 talloc_steal(new_parent
, child
);
515 free a talloc pointer. This also frees all child pointers of this
518 return 0 if the memory is actually freed, otherwise -1. The memory
519 will not be freed if the ref_count is > 1 or the destructor (if
520 any) returns non-zero
522 int talloc_free(void *ptr
)
524 struct talloc_chunk
*tc
;
530 tc
= talloc_chunk_from_ptr(ptr
);
533 talloc_reference_destructor(tc
->refs
);
537 if (tc
->destructor
) {
538 talloc_destructor_t d
= tc
->destructor
;
539 if (d
== (talloc_destructor_t
)-1) {
542 tc
->destructor
= (talloc_destructor_t
)-1;
547 tc
->destructor
= NULL
;
550 talloc_free_children(ptr
);
553 _TLIST_REMOVE(tc
->parent
->child
, tc
);
554 if (tc
->parent
->child
) {
555 tc
->parent
->child
->parent
= tc
->parent
;
558 if (tc
->prev
) tc
->prev
->next
= tc
->next
;
559 if (tc
->next
) tc
->next
->prev
= tc
->prev
;
562 tc
->u
.magic
= TALLOC_MAGIC_FREE
;
571 A talloc version of realloc. The context argument is only used if
574 void *_talloc_realloc(const void *context
, void *ptr
, size_t size
, const char *name
)
576 struct talloc_chunk
*tc
;
579 /* size zero is equivalent to free() */
585 if (size
>= MAX_TALLOC_SIZE
) {
589 /* realloc(NULL) is equavalent to malloc() */
591 return talloc_named_const(context
, size
, name
);
594 tc
= talloc_chunk_from_ptr(ptr
);
596 /* don't allow realloc on referenced pointers */
601 /* by resetting magic we catch users of the old memory */
602 tc
->u
.magic
= TALLOC_MAGIC_FREE
;
605 new_ptr
= malloc(size
+ sizeof(*tc
));
607 memcpy(new_ptr
, tc
, tc
->size
+ sizeof(*tc
));
611 new_ptr
= realloc(tc
, size
+ sizeof(*tc
));
614 tc
->u
.magic
= TALLOC_MAGIC
;
619 tc
->u
.magic
= TALLOC_MAGIC
;
621 tc
->parent
->child
= new_ptr
;
624 tc
->child
->parent
= new_ptr
;
635 talloc_set_name_const(tc
+1, name
);
637 return (void *)(tc
+1);
641 move a lump of memory from one talloc context to another return the
642 ptr on success, or NULL if it could not be transferred.
643 passing NULL as ptr will always return NULL with no side effects.
645 void *talloc_steal(const void *new_ctx
, const void *ptr
)
647 struct talloc_chunk
*tc
, *new_tc
;
653 if (new_ctx
== NULL
) {
654 new_ctx
= null_context
;
657 tc
= talloc_chunk_from_ptr(ptr
);
659 if (new_ctx
== NULL
) {
661 _TLIST_REMOVE(tc
->parent
->child
, tc
);
662 if (tc
->parent
->child
) {
663 tc
->parent
->child
->parent
= tc
->parent
;
666 if (tc
->prev
) tc
->prev
->next
= tc
->next
;
667 if (tc
->next
) tc
->next
->prev
= tc
->prev
;
670 tc
->parent
= tc
->next
= tc
->prev
= NULL
;
671 return discard_const_p(void, ptr
);
674 new_tc
= talloc_chunk_from_ptr(new_ctx
);
677 return discard_const_p(void, ptr
);
681 _TLIST_REMOVE(tc
->parent
->child
, tc
);
682 if (tc
->parent
->child
) {
683 tc
->parent
->child
->parent
= tc
->parent
;
686 if (tc
->prev
) tc
->prev
->next
= tc
->next
;
687 if (tc
->next
) tc
->next
->prev
= tc
->prev
;
691 if (new_tc
->child
) new_tc
->child
->parent
= NULL
;
692 _TLIST_ADD(new_tc
->child
, tc
);
694 return discard_const_p(void, ptr
);
698 return the total size of a talloc pool (subtree)
700 off_t
talloc_total_size(const void *ptr
)
703 struct talloc_chunk
*c
, *tc
;
712 tc
= talloc_chunk_from_ptr(ptr
);
715 for (c
=tc
->child
;c
;c
=c
->next
) {
716 total
+= talloc_total_size(c
+1);
722 return the total number of blocks in a talloc pool (subtree)
724 off_t
talloc_total_blocks(const void *ptr
)
727 struct talloc_chunk
*c
, *tc
= talloc_chunk_from_ptr(ptr
);
730 for (c
=tc
->child
;c
;c
=c
->next
) {
731 total
+= talloc_total_blocks(c
+1);
737 return the number of external references to a pointer
739 static int talloc_reference_count(const void *ptr
)
741 struct talloc_chunk
*tc
= talloc_chunk_from_ptr(ptr
);
742 struct talloc_reference_handle
*h
;
745 for (h
=tc
->refs
;h
;h
=h
->next
) {
752 report on memory usage by all children of a pointer, giving a full tree view
754 void talloc_report_depth(const void *ptr
, FILE *f
, int depth
)
756 struct talloc_chunk
*c
, *tc
= talloc_chunk_from_ptr(ptr
);
758 for (c
=tc
->child
;c
;c
=c
->next
) {
759 if (c
->name
== TALLOC_MAGIC_REFERENCE
) {
760 struct talloc_reference_handle
*handle
= (void *)(c
+1);
761 const char *name2
= talloc_get_name(handle
->ptr
);
762 fprintf(f
, "%*sreference to: %s\n", depth
*4, "", name2
);
764 const char *name
= talloc_get_name(c
+1);
765 fprintf(f
, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n",
768 (unsigned long)talloc_total_size(c
+1),
769 (unsigned long)talloc_total_blocks(c
+1),
770 talloc_reference_count(c
+1));
771 talloc_report_depth(c
+1, f
, depth
+1);
778 report on memory usage by all children of a pointer, giving a full tree view
780 void talloc_report_full(const void *ptr
, FILE *f
)
785 if (ptr
== NULL
) return;
787 fprintf(f
,"full talloc report on '%s' (total %lu bytes in %lu blocks)\n",
788 talloc_get_name(ptr
),
789 (unsigned long)talloc_total_size(ptr
),
790 (unsigned long)talloc_total_blocks(ptr
));
792 talloc_report_depth(ptr
, f
, 1);
797 report on memory usage by all children of a pointer
799 void talloc_report(const void *ptr
, FILE *f
)
801 struct talloc_chunk
*c
, *tc
;
806 if (ptr
== NULL
) return;
808 fprintf(f
,"talloc report on '%s' (total %lu bytes in %lu blocks)\n",
809 talloc_get_name(ptr
),
810 (unsigned long)talloc_total_size(ptr
),
811 (unsigned long)talloc_total_blocks(ptr
));
813 tc
= talloc_chunk_from_ptr(ptr
);
815 for (c
=tc
->child
;c
;c
=c
->next
) {
816 fprintf(f
, "\t%-30s contains %6lu bytes in %3lu blocks\n",
817 talloc_get_name(c
+1),
818 (unsigned long)talloc_total_size(c
+1),
819 (unsigned long)talloc_total_blocks(c
+1));
825 report on any memory hanging off the null context
827 static void talloc_report_null(void)
829 if (talloc_total_size(null_context
) != 0) {
830 talloc_report(null_context
, stderr
);
835 report on any memory hanging off the null context
837 static void talloc_report_null_full(void)
839 if (talloc_total_size(null_context
) != 0) {
840 talloc_report_full(null_context
, stderr
);
845 enable tracking of the NULL context
847 void talloc_enable_null_tracking(void)
849 if (null_context
== NULL
) {
850 null_context
= talloc_named_const(NULL
, 0, "null_context");
855 enable leak reporting on exit
857 void talloc_enable_leak_report(void)
859 talloc_enable_null_tracking();
860 atexit(talloc_report_null
);
864 enable full leak reporting on exit
866 void talloc_enable_leak_report_full(void)
868 talloc_enable_null_tracking();
869 atexit(talloc_report_null_full
);
873 talloc and zero memory.
875 void *_talloc_zero(const void *ctx
, size_t size
, const char *name
)
877 void *p
= talloc_named_const(ctx
, size
, name
);
880 memset(p
, '\0', size
);
888 memdup with a talloc.
890 void *_talloc_memdup(const void *t
, const void *p
, size_t size
, const char *name
)
892 void *newp
= talloc_named_const(t
, size
, name
);
895 memcpy(newp
, p
, size
);
904 char *talloc_strdup(const void *t
, const char *p
)
910 ret
= talloc_memdup(t
, p
, strlen(p
) + 1);
912 talloc_set_name_const(ret
, ret
);
918 strndup with a talloc
920 char *talloc_strndup(const void *t
, const char *p
, size_t n
)
925 for (len
=0; len
<n
&& p
[len
]; len
++) ;
927 ret
= _talloc(t
, len
+ 1);
928 if (!ret
) { return NULL
; }
931 talloc_set_name_const(ret
, ret
);
937 #define VA_COPY(dest, src) va_copy(dest, src)
938 #elif defined(HAVE___VA_COPY)
939 #define VA_COPY(dest, src) __va_copy(dest, src)
941 #define VA_COPY(dest, src) (dest) = (src)
945 char *talloc_vasprintf(const void *t
, const char *fmt
, va_list ap
)
953 len
= vsnprintf(NULL
, 0, fmt
, ap2
);
955 ret
= _talloc(t
, len
+1);
958 vsnprintf(ret
, len
+1, fmt
, ap2
);
959 talloc_set_name_const(ret
, ret
);
967 Perform string formatting, and return a pointer to newly allocated
968 memory holding the result, inside a memory pool.
970 char *talloc_asprintf(const void *t
, const char *fmt
, ...)
976 ret
= talloc_vasprintf(t
, fmt
, ap
);
983 * Realloc @p s to append the formatted result of @p fmt and @p ap,
984 * and return @p s, which may have moved. Good for gradually
985 * accumulating output into a string buffer.
988 static char *talloc_vasprintf_append(char *s
, const char *fmt
, va_list ap
) PRINTF_ATTRIBUTE(2,0);
990 static char *talloc_vasprintf_append(char *s
, const char *fmt
, va_list ap
)
996 return talloc_vasprintf(NULL
, fmt
, ap
);
1002 len
= vsnprintf(NULL
, 0, fmt
, ap2
);
1004 s
= talloc_realloc(NULL
, s
, char, s_len
+ len
+1);
1005 if (!s
) return NULL
;
1009 vsnprintf(s
+s_len
, len
+1, fmt
, ap2
);
1010 talloc_set_name_const(s
, s
);
1016 Realloc @p s to append the formatted result of @p fmt and return @p
1017 s, which may have moved. Good for gradually accumulating output
1018 into a string buffer.
1020 char *talloc_asprintf_append(char *s
, const char *fmt
, ...)
1025 s
= talloc_vasprintf_append(s
, fmt
, ap
);
1031 alloc an array, checking for integer overflow in the array size
1033 void *_talloc_array(const void *ctx
, size_t el_size
, unsigned count
, const char *name
)
1035 if (count
>= MAX_TALLOC_SIZE
/el_size
) {
1038 return talloc_named_const(ctx
, el_size
* count
, name
);
1042 alloc an zero array, checking for integer overflow in the array size
1044 void *_talloc_zero_array(const void *ctx
, size_t el_size
, unsigned count
, const char *name
)
1046 if (count
>= MAX_TALLOC_SIZE
/el_size
) {
1049 return _talloc_zero(ctx
, el_size
* count
, name
);
1054 realloc an array, checking for integer overflow in the array size
1056 void *_talloc_realloc_array(const void *ctx
, void *ptr
, size_t el_size
, unsigned count
, const char *name
)
1058 if (count
>= MAX_TALLOC_SIZE
/el_size
) {
1061 return _talloc_realloc(ctx
, ptr
, el_size
* count
, name
);
1065 a function version of talloc_realloc(), so it can be passed as a function pointer
1066 to libraries that want a realloc function (a realloc function encapsulates
1067 all the basic capabilities of an allocation library, which is why this is useful)
1069 void *talloc_realloc_fn(const void *context
, void *ptr
, size_t size
)
1071 return _talloc_realloc(context
, ptr
, size
, NULL
);
1075 static void talloc_autofree(void)
1077 talloc_free(cleanup_context
);
1078 cleanup_context
= NULL
;
1082 return a context which will be auto-freed on exit
1083 this is useful for reducing the noise in leak reports
1085 void *talloc_autofree_context(void)
1087 if (cleanup_context
== NULL
) {
1088 cleanup_context
= talloc_named_const(NULL
, 0, "autofree_context");
1089 atexit(talloc_autofree
);
1091 return cleanup_context
;
1094 size_t talloc_get_size(const void *context
)
1096 struct talloc_chunk
*tc
;
1098 if (context
== NULL
)
1101 tc
= talloc_chunk_from_ptr(context
);