File: | utils/talloc.c |
Warning: | line 412, column 7 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | */ | |||
107 | static void *null_context; | |||
108 | static void *autofree_context; | |||
109 | ||||
110 | struct talloc_reference_handle { | |||
111 | struct talloc_reference_handle *next, *prev; | |||
112 | void *ptr; | |||
113 | }; | |||
114 | ||||
115 | typedef int (*talloc_destructor_t)(void *); | |||
116 | ||||
117 | struct 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 */ | |||
132 | static 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 ) \ | |||
148 | do { \ | |||
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) \ | |||
162 | do { \ | |||
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 | */ | |||
177 | static 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 | ||||
191 | void *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 | */ | |||
200 | const 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 | */ | |||
209 | static 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 | */ | |||
257 | void _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 | */ | |||
266 | int 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 | */ | |||
279 | static 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 | */ | |||
290 | static 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 | */ | |||
299 | static 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 | */ | |||
322 | void *_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 | */ | |||
347 | static inline int _talloc_free(void *ptr) | |||
348 | { | |||
349 | struct talloc_chunk *tc; | |||
350 | ||||
351 | if (unlikely(ptr == NULL)__builtin_expect(!!(ptr == ((void*)0)), 0)) { | |||
352 | return -1; | |||
353 | } | |||
354 | ||||
355 | tc = talloc_chunk_from_ptr(ptr); | |||
356 | ||||
357 | if (unlikely(tc->refs)__builtin_expect(!!(tc->refs), 0)) { | |||
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); | |||
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)) { | |||
375 | /* we have a free loop - stop looping */ | |||
376 | return 0; | |||
377 | } | |||
378 | ||||
379 | if (unlikely(tc->destructor)__builtin_expect(!!(tc->destructor), 0)) { | |||
380 | talloc_destructor_t d = tc->destructor; | |||
381 | if (d == (talloc_destructor_t)-1) { | |||
382 | return -1; | |||
383 | } | |||
384 | tc->destructor = (talloc_destructor_t)-1; | |||
385 | if (d(ptr) == -1) { | |||
386 | tc->destructor = d; | |||
387 | return -1; | |||
388 | } | |||
389 | tc->destructor = NULL((void*)0); | |||
390 | } | |||
391 | ||||
392 | if (tc->parent) { | |||
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; | |||
399 | if (tc->next) tc->next->prev = tc->prev; | |||
400 | } | |||
401 | ||||
402 | tc->flags |= TALLOC_FLAG_LOOP0x02; | |||
403 | ||||
404 | while (tc->child) { | |||
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)) { | |||
| ||||
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)); | |||
415 | } | |||
416 | if (unlikely(_talloc_free(child) == -1)__builtin_expect(!!(_talloc_free(child) == -1), 0)) { | |||
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); | |||
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 | */ | |||
435 | void *_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 | */ | |||
494 | static 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 | */ | |||
522 | int 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 | */ | |||
574 | static 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 | ||||
576 | static 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 | */ | |||
589 | const 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 | */ | |||
605 | void *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 | */ | |||
629 | const 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 | */ | |||
646 | void *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 | */ | |||
661 | void *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 | */ | |||
694 | void 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 | */ | |||
729 | void *_talloc(const void *context, size_t size) | |||
730 | { | |||
731 | return __talloc(context, size); | |||
732 | } | |||
733 | ||||
734 | /* | |||
735 | externally callable talloc_set_name_const() | |||
736 | */ | |||
737 | void 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 | */ | |||
747 | void *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 | */ | |||
760 | int 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 | */ | |||
771 | void *_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 | */ | |||
841 | void *_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 | */ | |||
852 | size_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 | */ | |||
885 | size_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 | */ | |||
909 | size_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 | */ | |||
924 | void 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 | ||||
962 | static 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 | */ | |||
1008 | void 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 | */ | |||
1017 | void 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 | */ | |||
1025 | void 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 | */ | |||
1033 | static 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 | */ | |||
1043 | static 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 | */ | |||
1053 | void 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 | */ | |||
1063 | void 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 | */ | |||
1072 | void 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 | */ | |||
1081 | void 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 | */ | |||
1090 | void *_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 | */ | |||
1104 | void *_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 | */ | |||
1118 | char *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 | */ | |||
1134 | char *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 | */ | |||
1160 | char *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 | ||||
1183 | char *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 | */ | |||
1214 | char *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 | **/ | |||
1231 | char *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 | */ | |||
1276 | char *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 | */ | |||
1289 | void *_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 | */ | |||
1300 | void *_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 | */ | |||
1311 | void *_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 | */ | |||
1324 | void *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 | ||||
1330 | static int talloc_autofree_destructor(void *ptr) | |||
1331 | { | |||
1332 | autofree_context = NULL((void*)0); | |||
1333 | return 0; | |||
1334 | } | |||
1335 | ||||
1336 | static void talloc_autofree(void) | |||
1337 | { | |||
1338 | _talloc_free(autofree_context); | |||
| ||||
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 | */ | |||
1345 | void *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 | ||||
1355 | size_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 | */ | |||
1370 | void *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 | */ | |||
1394 | void 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 | */ | |||
1418 | int 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 | } |