Bug Summary

File:utils/talloc.c
Warning:line 412, column 7
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

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