Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: third_party/talloc/talloc.c

Issue 2282793002: Remove unused third_party/talloc (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/talloc/talloc.h ('k') | third_party/talloc/talloc.exports » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 3 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, see <http://www.gnu.org/licenses/>.
27 */
28
29 /*
30 inspired by http://swapped.cc/halloc/
31 */
32
33 /* Commented out for building within Chromium */
34 /* #include "replace.h" */
35 #include "talloc.h"
36
37 #ifdef TALLOC_BUILD_VERSION_MAJOR
38 #if (TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR)
39 #error "TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR"
40 #endif
41 #endif
42
43 #ifdef TALLOC_BUILD_VERSION_MINOR
44 #if (TALLOC_VERSION_MINOR != TALLOC_BUILD_VERSION_MINOR)
45 #error "TALLOC_VERSION_MINOR != TALLOC_BUILD_VERSION_MINOR"
46 #endif
47 #endif
48
49 /* use this to force every realloc to change the pointer, to stress test
50 code that might not cope */
51 #define ALWAYS_REALLOC 0
52
53
54 #define MAX_TALLOC_SIZE 0x10000000
55 #define TALLOC_MAGIC_BASE 0xe814ec70
56 #define TALLOC_MAGIC ( \
57 TALLOC_MAGIC_BASE + \
58 (TALLOC_VERSION_MAJOR << 12) + \
59 (TALLOC_VERSION_MINOR << 4) \
60 )
61
62 #define TALLOC_FLAG_FREE 0x01
63 #define TALLOC_FLAG_LOOP 0x02
64 #define TALLOC_FLAG_POOL 0x04 /* This is a talloc pool */
65 #define TALLOC_FLAG_POOLMEM 0x08 /* This is allocated in a pool */
66 #define TALLOC_MAGIC_REFERENCE ((const char *)1)
67
68 /* by default we abort when given a bad pointer (such as when talloc_free() is c alled
69 on a pointer that came from malloc() */
70 #ifndef TALLOC_ABORT
71 #define TALLOC_ABORT(reason) abort()
72 #endif
73
74 #ifndef discard_const_p
75 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
76 # define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
77 #else
78 # define discard_const_p(type, ptr) ((type *)(ptr))
79 #endif
80 #endif
81
82 /* these macros gain us a few percent of speed on gcc */
83 #if (__GNUC__ >= 3)
84 /* the strange !! is to ensure that __builtin_expect() takes either 0 or 1
85 as its first argument */
86 #ifndef likely
87 #define likely(x) __builtin_expect(!!(x), 1)
88 #endif
89 #ifndef unlikely
90 #define unlikely(x) __builtin_expect(!!(x), 0)
91 #endif
92 #else
93 #ifndef likely
94 #define likely(x) (x)
95 #endif
96 #ifndef unlikely
97 #define unlikely(x) (x)
98 #endif
99 #endif
100
101 /* inline isn't supported in C files in Visual Studio 2008 on Windows */
102 #ifdef _MSC_VER
103 #define INLINE
104 #else
105 #define INLINE inline
106 #endif
107
108 /* this null_context is only used if talloc_enable_leak_report() or
109 talloc_enable_leak_report_full() is called, otherwise it remains
110 NULL
111 */
112 static void *null_context;
113 static void *autofree_context;
114
115 struct talloc_reference_handle {
116 struct talloc_reference_handle *next, *prev;
117 void *ptr;
118 const char *location;
119 };
120
121 typedef int (*talloc_destructor_t)(void *);
122
123 struct talloc_chunk {
124 struct talloc_chunk *next, *prev;
125 struct talloc_chunk *parent, *child;
126 struct talloc_reference_handle *refs;
127 talloc_destructor_t destructor;
128 const char *name;
129 size_t size;
130 unsigned flags;
131
132 /*
133 * "pool" has dual use:
134 *
135 * For the talloc pool itself (i.e. TALLOC_FLAG_POOL is set), "pool"
136 * marks the end of the currently allocated area.
137 *
138 * For members of the pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool"
139 * is a pointer to the struct talloc_chunk of the pool that it was
140 * allocated from. This way children can quickly find the pool to chew
141 * from.
142 */
143 void *pool;
144 };
145
146 /* 16 byte alignment seems to keep everyone happy */
147 #define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15)
148 #define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc))
149
150 int talloc_version_major(void)
151 {
152 return TALLOC_VERSION_MAJOR;
153 }
154
155 int talloc_version_minor(void)
156 {
157 return TALLOC_VERSION_MINOR;
158 }
159
160 static void (*talloc_log_fn)(const char *message);
161
162 void talloc_set_log_fn(void (*log_fn)(const char *message))
163 {
164 talloc_log_fn = log_fn;
165 }
166
167 static void talloc_log(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
168 static void talloc_log(const char *fmt, ...)
169 {
170 va_list ap;
171 char *message;
172
173 if (!talloc_log_fn) {
174 return;
175 }
176
177 va_start(ap, fmt);
178 message = talloc_vasprintf(NULL, fmt, ap);
179 va_end(ap);
180
181 talloc_log_fn(message);
182 talloc_free(message);
183 }
184
185 static void talloc_log_stderr(const char *message)
186 {
187 fprintf(stderr, "%s", message);
188 }
189
190 void talloc_set_log_stderr(void)
191 {
192 talloc_set_log_fn(talloc_log_stderr);
193 }
194
195 static void (*talloc_abort_fn)(const char *reason);
196
197 void talloc_set_abort_fn(void (*abort_fn)(const char *reason))
198 {
199 talloc_abort_fn = abort_fn;
200 }
201
202 static void talloc_abort(const char *reason)
203 {
204 talloc_log("%s\n", reason);
205
206 if (!talloc_abort_fn) {
207 TALLOC_ABORT(reason);
208 }
209
210 talloc_abort_fn(reason);
211 }
212
213 static void talloc_abort_magic(unsigned magic)
214 {
215 unsigned striped = magic - TALLOC_MAGIC_BASE;
216 unsigned major = (striped & 0xFFFFF000) >> 12;
217 unsigned minor = (striped & 0x00000FF0) >> 4;
218 talloc_log("Bad talloc magic[0x%08X/%u/%u] expected[0x%08X/%u/%u]\n",
219 magic, major, minor,
220 TALLOC_MAGIC, TALLOC_VERSION_MAJOR, TALLOC_VERSION_MINOR);
221 talloc_abort("Bad talloc magic value - wrong talloc version used/mixed") ;
222 }
223
224 static void talloc_abort_double_free(void)
225 {
226 talloc_abort("Bad talloc magic value - double free");
227 }
228
229 static void talloc_abort_unknown_value(void)
230 {
231 talloc_abort("Bad talloc magic value - unknown value");
232 }
233
234 /* panic if we get a bad magic value */
235 static INLINE struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
236 {
237 const char *pp = (const char *)ptr;
238 struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_H DR_SIZE);
239 if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) {
240 if ((tc->flags & (~0xFFF)) == TALLOC_MAGIC_BASE) {
241 talloc_abort_magic(tc->flags & (~0xF));
242 return NULL;
243 }
244
245 if (tc->flags & TALLOC_FLAG_FREE) {
246 talloc_log("talloc: double free error - first free may b e at %s\n", tc->name);
247 talloc_abort_double_free();
248 return NULL;
249 } else {
250 talloc_abort_unknown_value();
251 return NULL;
252 }
253 }
254 return tc;
255 }
256
257 /* hook into the front of the list */
258 #define _TLIST_ADD(list, p) \
259 do { \
260 if (!(list)) { \
261 (list) = (p); \
262 (p)->next = (p)->prev = NULL; \
263 } else { \
264 (list)->prev = (p); \
265 (p)->next = (list); \
266 (p)->prev = NULL; \
267 (list) = (p); \
268 }\
269 } while (0)
270
271 /* remove an element from a list - element doesn't have to be in list. */
272 #define _TLIST_REMOVE(list, p) \
273 do { \
274 if ((p) == (list)) { \
275 (list) = (p)->next; \
276 if (list) (list)->prev = NULL; \
277 } else { \
278 if ((p)->prev) (p)->prev->next = (p)->next; \
279 if ((p)->next) (p)->next->prev = (p)->prev; \
280 } \
281 if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
282 } while (0)
283
284
285 /*
286 return the parent chunk of a pointer
287 */
288 static INLINE struct talloc_chunk *talloc_parent_chunk(const void *ptr)
289 {
290 struct talloc_chunk *tc;
291
292 if (unlikely(ptr == NULL)) {
293 return NULL;
294 }
295
296 tc = talloc_chunk_from_ptr(ptr);
297 while (tc->prev) tc=tc->prev;
298
299 return tc->parent;
300 }
301
302 void *talloc_parent(const void *ptr)
303 {
304 struct talloc_chunk *tc = talloc_parent_chunk(ptr);
305 return tc? TC_PTR_FROM_CHUNK(tc) : NULL;
306 }
307
308 /*
309 find parents name
310 */
311 const char *talloc_parent_name(const void *ptr)
312 {
313 struct talloc_chunk *tc = talloc_parent_chunk(ptr);
314 return tc? tc->name : NULL;
315 }
316
317 /*
318 A pool carries an in-pool object count count in the first 16 bytes.
319 bytes. This is done to support talloc_steal() to a parent outside of the
320 pool. The count includes the pool itself, so a talloc_free() on a pool will
321 only destroy the pool if the count has dropped to zero. A talloc_free() of a
322 pool member will reduce the count, and eventually also call free(3) on the
323 pool memory.
324
325 The object count is not put into "struct talloc_chunk" because it is only
326 relevant for talloc pools and the alignment to 16 bytes would increase the
327 memory footprint of each talloc chunk by those 16 bytes.
328 */
329
330 #define TALLOC_POOL_HDR_SIZE 16
331
332 static unsigned int *talloc_pool_objectcount(struct talloc_chunk *tc)
333 {
334 return (unsigned int *)((char *)tc + sizeof(struct talloc_chunk));
335 }
336
337 /*
338 Allocate from a pool
339 */
340
341 static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent,
342 size_t size)
343 {
344 struct talloc_chunk *pool_ctx = NULL;
345 size_t space_left;
346 struct talloc_chunk *result;
347 size_t chunk_size;
348
349 if (parent == NULL) {
350 return NULL;
351 }
352
353 if (parent->flags & TALLOC_FLAG_POOL) {
354 pool_ctx = parent;
355 }
356 else if (parent->flags & TALLOC_FLAG_POOLMEM) {
357 pool_ctx = (struct talloc_chunk *)parent->pool;
358 }
359
360 if (pool_ctx == NULL) {
361 return NULL;
362 }
363
364 space_left = ((char *)pool_ctx + TC_HDR_SIZE + pool_ctx->size)
365 - ((char *)pool_ctx->pool);
366
367 /*
368 * Align size to 16 bytes
369 */
370 chunk_size = ((size + 15) & ~15);
371
372 if (space_left < chunk_size) {
373 return NULL;
374 }
375
376 result = (struct talloc_chunk *)pool_ctx->pool;
377
378 #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
379 VALGRIND_MAKE_MEM_UNDEFINED(result, size);
380 #endif
381
382 pool_ctx->pool = (void *)((char *)result + chunk_size);
383
384 result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM;
385 result->pool = pool_ctx;
386
387 *talloc_pool_objectcount(pool_ctx) += 1;
388
389 return result;
390 }
391
392 /*
393 Allocate a bit of memory as a child of an existing pointer
394 */
395 static INLINE void *__talloc(const void *context, size_t size)
396 {
397 struct talloc_chunk *tc = NULL;
398
399 if (unlikely(context == NULL)) {
400 context = null_context;
401 }
402
403 if (unlikely(size >= MAX_TALLOC_SIZE)) {
404 return NULL;
405 }
406
407 if (context != NULL) {
408 tc = talloc_alloc_pool(talloc_chunk_from_ptr(context),
409 TC_HDR_SIZE+size);
410 }
411
412 if (tc == NULL) {
413 tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size);
414 if (unlikely(tc == NULL)) return NULL;
415 tc->flags = TALLOC_MAGIC;
416 tc->pool = NULL;
417 }
418
419 tc->size = size;
420 tc->destructor = NULL;
421 tc->child = NULL;
422 tc->name = NULL;
423 tc->refs = NULL;
424
425 if (likely(context)) {
426 struct talloc_chunk *parent = talloc_chunk_from_ptr(context);
427
428 if (parent->child) {
429 parent->child->parent = NULL;
430 tc->next = parent->child;
431 tc->next->prev = tc;
432 } else {
433 tc->next = NULL;
434 }
435 tc->parent = parent;
436 tc->prev = NULL;
437 parent->child = tc;
438 } else {
439 tc->next = tc->prev = tc->parent = NULL;
440 }
441
442 return TC_PTR_FROM_CHUNK(tc);
443 }
444
445 /*
446 * Create a talloc pool
447 */
448
449 void *talloc_pool(const void *context, size_t size)
450 {
451 void *result = __talloc(context, size + TALLOC_POOL_HDR_SIZE);
452 struct talloc_chunk *tc;
453
454 if (unlikely(result == NULL)) {
455 return NULL;
456 }
457
458 tc = talloc_chunk_from_ptr(result);
459
460 tc->flags |= TALLOC_FLAG_POOL;
461 tc->pool = (char *)result + TALLOC_POOL_HDR_SIZE;
462
463 *talloc_pool_objectcount(tc) = 1;
464
465 #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
466 VALGRIND_MAKE_MEM_NOACCESS(tc->pool, size);
467 #endif
468
469 return result;
470 }
471
472 /*
473 setup a destructor to be called on free of a pointer
474 the destructor should return 0 on success, or -1 on failure.
475 if the destructor fails then the free is failed, and the memory can
476 be continued to be used
477 */
478 void _talloc_set_destructor(const void *ptr, int (*destructor)(void *))
479 {
480 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
481 tc->destructor = destructor;
482 }
483
484 /*
485 increase the reference count on a piece of memory.
486 */
487 int talloc_increase_ref_count(const void *ptr)
488 {
489 if (unlikely(!talloc_reference(null_context, ptr))) {
490 return -1;
491 }
492 return 0;
493 }
494
495 /*
496 helper for talloc_reference()
497
498 this is referenced by a function pointer and should not be inline
499 */
500 static int talloc_reference_destructor(struct talloc_reference_handle *handle)
501 {
502 struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr);
503 _TLIST_REMOVE(ptr_tc->refs, handle);
504 return 0;
505 }
506
507 /*
508 more efficient way to add a name to a pointer - the name must point to a
509 true string constant
510 */
511 static INLINE void _talloc_set_name_const(const void *ptr, const char *name)
512 {
513 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
514 tc->name = name;
515 }
516
517 /*
518 internal talloc_named_const()
519 */
520 static INLINE void *_talloc_named_const(const void *context, size_t size, const char *name)
521 {
522 void *ptr;
523
524 ptr = __talloc(context, size);
525 if (unlikely(ptr == NULL)) {
526 return NULL;
527 }
528
529 _talloc_set_name_const(ptr, name);
530
531 return ptr;
532 }
533
534 /*
535 make a secondary reference to a pointer, hanging off the given context.
536 the pointer remains valid until both the original caller and this given
537 context are freed.
538
539 the major use for this is when two different structures need to reference the
540 same underlying data, and you want to be able to free the two instances separa tely,
541 and in either order
542 */
543 void *_talloc_reference_loc(const void *context, const void *ptr, const char *lo cation)
544 {
545 struct talloc_chunk *tc;
546 struct talloc_reference_handle *handle;
547 if (unlikely(ptr == NULL)) return NULL;
548
549 tc = talloc_chunk_from_ptr(ptr);
550 handle = (struct talloc_reference_handle *)_talloc_named_const(context,
551 sizeof(struct talloc_referenc e_handle),
552 TALLOC_MAGIC_REFERENCE);
553 if (unlikely(handle == NULL)) return NULL;
554
555 /* note that we hang the destructor off the handle, not the
556 main context as that allows the caller to still setup their
557 own destructor on the context if they want to */
558 talloc_set_destructor(handle, talloc_reference_destructor);
559 handle->ptr = discard_const_p(void, ptr);
560 handle->location = location;
561 _TLIST_ADD(tc->refs, handle);
562 return handle->ptr;
563 }
564
565 static void *_talloc_steal_internal(const void *new_ctx, const void *ptr);
566
567 /*
568 internal talloc_free call
569 */
570 static INLINE int _talloc_free_internal(void *ptr, const char *location)
571 {
572 struct talloc_chunk *tc;
573
574 if (unlikely(ptr == NULL)) {
575 return -1;
576 }
577
578 tc = talloc_chunk_from_ptr(ptr);
579
580 if (unlikely(tc->refs)) {
581 int is_child;
582 /* check this is a reference from a child or grantchild
583 * back to it's parent or grantparent
584 *
585 * in that case we need to remove the reference and
586 * call another instance of talloc_free() on the current
587 * pointer.
588 */
589 is_child = talloc_is_parent(tc->refs, ptr);
590 _talloc_free_internal(tc->refs, location);
591 if (is_child) {
592 return _talloc_free_internal(ptr, location);
593 }
594 return -1;
595 }
596
597 if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) {
598 /* we have a free loop - stop looping */
599 return 0;
600 }
601
602 if (unlikely(tc->destructor)) {
603 talloc_destructor_t d = tc->destructor;
604 if (d == (talloc_destructor_t)-1) {
605 return -1;
606 }
607 tc->destructor = (talloc_destructor_t)-1;
608 if (d(ptr) == -1) {
609 tc->destructor = d;
610 return -1;
611 }
612 tc->destructor = NULL;
613 }
614
615 if (tc->parent) {
616 _TLIST_REMOVE(tc->parent->child, tc);
617 if (tc->parent->child) {
618 tc->parent->child->parent = tc->parent;
619 }
620 } else {
621 if (tc->prev) tc->prev->next = tc->next;
622 if (tc->next) tc->next->prev = tc->prev;
623 }
624
625 tc->flags |= TALLOC_FLAG_LOOP;
626
627 while (tc->child) {
628 /* we need to work out who will own an abandoned child
629 if it cannot be freed. In priority order, the first
630 choice is owner of any remaining reference to this
631 pointer, the second choice is our parent, and the
632 final choice is the null context. */
633 void *child = TC_PTR_FROM_CHUNK(tc->child);
634 const void *new_parent = null_context;
635 if (unlikely(tc->child->refs)) {
636 struct talloc_chunk *p = talloc_parent_chunk(tc->child-> refs);
637 if (p) new_parent = TC_PTR_FROM_CHUNK(p);
638 }
639 if (unlikely(_talloc_free_internal(child, location) == -1)) {
640 if (new_parent == null_context) {
641 struct talloc_chunk *p = talloc_parent_chunk(ptr );
642 if (p) new_parent = TC_PTR_FROM_CHUNK(p);
643 }
644 _talloc_steal_internal(new_parent, child);
645 }
646 }
647
648 tc->flags |= TALLOC_FLAG_FREE;
649
650 /* we mark the freed memory with where we called the free
651 * from. This means on a double free error we can report where
652 * the first free came from
653 */
654 tc->name = location;
655
656 if (tc->flags & (TALLOC_FLAG_POOL|TALLOC_FLAG_POOLMEM)) {
657 struct talloc_chunk *pool;
658 unsigned int *pool_object_count;
659
660 pool = (tc->flags & TALLOC_FLAG_POOL)
661 ? tc : (struct talloc_chunk *)tc->pool;
662
663 pool_object_count = talloc_pool_objectcount(pool);
664
665 if (*pool_object_count == 0) {
666 talloc_abort("Pool object count zero!");
667 return 0;
668 }
669
670 *pool_object_count -= 1;
671
672 if (*pool_object_count == 0) {
673 free(pool);
674 }
675 }
676 else {
677 free(tc);
678 }
679 return 0;
680 }
681
682 /*
683 move a lump of memory from one talloc context to another return the
684 ptr on success, or NULL if it could not be transferred.
685 passing NULL as ptr will always return NULL with no side effects.
686 */
687 static void *_talloc_steal_internal(const void *new_ctx, const void *ptr)
688 {
689 struct talloc_chunk *tc, *new_tc;
690
691 if (unlikely(!ptr)) {
692 return NULL;
693 }
694
695 if (unlikely(new_ctx == NULL)) {
696 new_ctx = null_context;
697 }
698
699 tc = talloc_chunk_from_ptr(ptr);
700
701 if (unlikely(new_ctx == NULL)) {
702 if (tc->parent) {
703 _TLIST_REMOVE(tc->parent->child, tc);
704 if (tc->parent->child) {
705 tc->parent->child->parent = tc->parent;
706 }
707 } else {
708 if (tc->prev) tc->prev->next = tc->next;
709 if (tc->next) tc->next->prev = tc->prev;
710 }
711
712 tc->parent = tc->next = tc->prev = NULL;
713 return discard_const_p(void, ptr);
714 }
715
716 new_tc = talloc_chunk_from_ptr(new_ctx);
717
718 if (unlikely(tc == new_tc || tc->parent == new_tc)) {
719 return discard_const_p(void, ptr);
720 }
721
722 if (tc->parent) {
723 _TLIST_REMOVE(tc->parent->child, tc);
724 if (tc->parent->child) {
725 tc->parent->child->parent = tc->parent;
726 }
727 } else {
728 if (tc->prev) tc->prev->next = tc->next;
729 if (tc->next) tc->next->prev = tc->prev;
730 }
731
732 tc->parent = new_tc;
733 if (new_tc->child) new_tc->child->parent = NULL;
734 _TLIST_ADD(new_tc->child, tc);
735
736 return discard_const_p(void, ptr);
737 }
738
739 /*
740 move a lump of memory from one talloc context to another return the
741 ptr on success, or NULL if it could not be transferred.
742 passing NULL as ptr will always return NULL with no side effects.
743 */
744 void *_talloc_steal_loc(const void *new_ctx, const void *ptr, const char *locati on)
745 {
746 struct talloc_chunk *tc;
747
748 if (unlikely(ptr == NULL)) {
749 return NULL;
750 }
751
752 tc = talloc_chunk_from_ptr(ptr);
753
754 if (unlikely(tc->refs != NULL) && talloc_parent(ptr) != new_ctx) {
755 struct talloc_reference_handle *h;
756
757 talloc_log("WARNING: talloc_steal with references at %s\n",
758 location);
759
760 for (h=tc->refs; h; h=h->next) {
761 talloc_log("\treference at %s\n",
762 h->location);
763 }
764 }
765
766 return _talloc_steal_internal(new_ctx, ptr);
767 }
768
769 /*
770 this is like a talloc_steal(), but you must supply the old
771 parent. This resolves the ambiguity in a talloc_steal() which is
772 called on a context that has more than one parent (via references)
773
774 The old parent can be either a reference or a parent
775 */
776 void *talloc_reparent(const void *old_parent, const void *new_parent, const void *ptr)
777 {
778 struct talloc_chunk *tc;
779 struct talloc_reference_handle *h;
780
781 if (unlikely(ptr == NULL)) {
782 return NULL;
783 }
784
785 if (old_parent == talloc_parent(ptr)) {
786 return _talloc_steal_internal(new_parent, ptr);
787 }
788
789 tc = talloc_chunk_from_ptr(ptr);
790 for (h=tc->refs;h;h=h->next) {
791 if (talloc_parent(h) == old_parent) {
792 if (_talloc_steal_internal(new_parent, h) != h) {
793 return NULL;
794 }
795 return discard_const_p(void, ptr);
796 }
797 }
798
799 /* it wasn't a parent */
800 return NULL;
801 }
802
803 /*
804 remove a secondary reference to a pointer. This undo's what
805 talloc_reference() has done. The context and pointer arguments
806 must match those given to a talloc_reference()
807 */
808 static INLINE int talloc_unreference(const void *context, const void *ptr)
809 {
810 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
811 struct talloc_reference_handle *h;
812
813 if (unlikely(context == NULL)) {
814 context = null_context;
815 }
816
817 for (h=tc->refs;h;h=h->next) {
818 struct talloc_chunk *p = talloc_parent_chunk(h);
819 if (p == NULL) {
820 if (context == NULL) break;
821 } else if (TC_PTR_FROM_CHUNK(p) == context) {
822 break;
823 }
824 }
825 if (h == NULL) {
826 return -1;
827 }
828
829 return _talloc_free_internal(h, __location__);
830 }
831
832 /*
833 remove a specific parent context from a pointer. This is a more
834 controlled varient of talloc_free()
835 */
836 int talloc_unlink(const void *context, void *ptr)
837 {
838 struct talloc_chunk *tc_p, *new_p;
839 void *new_parent;
840
841 if (ptr == NULL) {
842 return -1;
843 }
844
845 if (context == NULL) {
846 context = null_context;
847 }
848
849 if (talloc_unreference(context, ptr) == 0) {
850 return 0;
851 }
852
853 if (context == NULL) {
854 if (talloc_parent_chunk(ptr) != NULL) {
855 return -1;
856 }
857 } else {
858 if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) {
859 return -1;
860 }
861 }
862
863 tc_p = talloc_chunk_from_ptr(ptr);
864
865 if (tc_p->refs == NULL) {
866 return _talloc_free_internal(ptr, __location__);
867 }
868
869 new_p = talloc_parent_chunk(tc_p->refs);
870 if (new_p) {
871 new_parent = TC_PTR_FROM_CHUNK(new_p);
872 } else {
873 new_parent = NULL;
874 }
875
876 if (talloc_unreference(new_parent, ptr) != 0) {
877 return -1;
878 }
879
880 _talloc_steal_internal(new_parent, ptr);
881
882 return 0;
883 }
884
885 /*
886 add a name to an existing pointer - va_list version
887 */
888 static INLINE const char *talloc_set_name_v(const void *ptr, const char *fmt, va _list ap) PRINTF_ATTRIBUTE(2,0);
889
890 static INLINE const char *talloc_set_name_v(const void *ptr, const char *fmt, va _list ap)
891 {
892 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
893 tc->name = talloc_vasprintf(ptr, fmt, ap);
894 if (likely(tc->name)) {
895 _talloc_set_name_const(tc->name, ".name");
896 }
897 return tc->name;
898 }
899
900 /*
901 add a name to an existing pointer
902 */
903 const char *talloc_set_name(const void *ptr, const char *fmt, ...)
904 {
905 const char *name;
906 va_list ap;
907 va_start(ap, fmt);
908 name = talloc_set_name_v(ptr, fmt, ap);
909 va_end(ap);
910 return name;
911 }
912
913
914 /*
915 create a named talloc pointer. Any talloc pointer can be named, and
916 talloc_named() operates just like talloc() except that it allows you
917 to name the pointer.
918 */
919 void *talloc_named(const void *context, size_t size, const char *fmt, ...)
920 {
921 va_list ap;
922 void *ptr;
923 const char *name;
924
925 ptr = __talloc(context, size);
926 if (unlikely(ptr == NULL)) return NULL;
927
928 va_start(ap, fmt);
929 name = talloc_set_name_v(ptr, fmt, ap);
930 va_end(ap);
931
932 if (unlikely(name == NULL)) {
933 _talloc_free_internal(ptr, __location__);
934 return NULL;
935 }
936
937 return ptr;
938 }
939
940 /*
941 return the name of a talloc ptr, or "UNNAMED"
942 */
943 const char *talloc_get_name(const void *ptr)
944 {
945 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
946 if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) {
947 return ".reference";
948 }
949 if (likely(tc->name)) {
950 return tc->name;
951 }
952 return "UNNAMED";
953 }
954
955
956 /*
957 check if a pointer has the given name. If it does, return the pointer,
958 otherwise return NULL
959 */
960 void *talloc_check_name(const void *ptr, const char *name)
961 {
962 const char *pname;
963 if (unlikely(ptr == NULL)) return NULL;
964 pname = talloc_get_name(ptr);
965 if (likely(pname == name || strcmp(pname, name) == 0)) {
966 return discard_const_p(void, ptr);
967 }
968 return NULL;
969 }
970
971 static void talloc_abort_type_missmatch(const char *location,
972 const char *name,
973 const char *expected)
974 {
975 const char *reason;
976
977 reason = talloc_asprintf(NULL,
978 "%s: Type mismatch: name[%s] expected[%s]",
979 location,
980 name?name:"NULL",
981 expected);
982 if (!reason) {
983 reason = "Type mismatch";
984 }
985
986 talloc_abort(reason);
987 }
988
989 void *_talloc_get_type_abort(const void *ptr, const char *name, const char *loca tion)
990 {
991 const char *pname;
992
993 if (unlikely(ptr == NULL)) {
994 talloc_abort_type_missmatch(location, NULL, name);
995 return NULL;
996 }
997
998 pname = talloc_get_name(ptr);
999 if (likely(pname == name || strcmp(pname, name) == 0)) {
1000 return discard_const_p(void, ptr);
1001 }
1002
1003 talloc_abort_type_missmatch(location, pname, name);
1004 return NULL;
1005 }
1006
1007 /*
1008 this is for compatibility with older versions of talloc
1009 */
1010 void *talloc_init(const char *fmt, ...)
1011 {
1012 va_list ap;
1013 void *ptr;
1014 const char *name;
1015
1016 /*
1017 * samba3 expects talloc_report_depth_cb(NULL, ...)
1018 * reports all talloc'ed memory, so we need to enable
1019 * null_tracking
1020 */
1021 talloc_enable_null_tracking();
1022
1023 ptr = __talloc(NULL, 0);
1024 if (unlikely(ptr == NULL)) return NULL;
1025
1026 va_start(ap, fmt);
1027 name = talloc_set_name_v(ptr, fmt, ap);
1028 va_end(ap);
1029
1030 if (unlikely(name == NULL)) {
1031 _talloc_free_internal(ptr, __location__);
1032 return NULL;
1033 }
1034
1035 return ptr;
1036 }
1037
1038 /*
1039 this is a replacement for the Samba3 talloc_destroy_pool functionality. It
1040 should probably not be used in new code. It's in here to keep the talloc
1041 code consistent across Samba 3 and 4.
1042 */
1043 void talloc_free_children(void *ptr)
1044 {
1045 struct talloc_chunk *tc;
1046
1047 if (unlikely(ptr == NULL)) {
1048 return;
1049 }
1050
1051 tc = talloc_chunk_from_ptr(ptr);
1052
1053 while (tc->child) {
1054 /* we need to work out who will own an abandoned child
1055 if it cannot be freed. In priority order, the first
1056 choice is owner of any remaining reference to this
1057 pointer, the second choice is our parent, and the
1058 final choice is the null context. */
1059 void *child = TC_PTR_FROM_CHUNK(tc->child);
1060 const void *new_parent = null_context;
1061 if (unlikely(tc->child->refs)) {
1062 struct talloc_chunk *p = talloc_parent_chunk(tc->child-> refs);
1063 if (p) new_parent = TC_PTR_FROM_CHUNK(p);
1064 }
1065 if (unlikely(talloc_free(child) == -1)) {
1066 if (new_parent == null_context) {
1067 struct talloc_chunk *p = talloc_parent_chunk(ptr );
1068 if (p) new_parent = TC_PTR_FROM_CHUNK(p);
1069 }
1070 _talloc_steal_internal(new_parent, child);
1071 }
1072 }
1073
1074 if ((tc->flags & TALLOC_FLAG_POOL)
1075 && (*talloc_pool_objectcount(tc) == 1)) {
1076 tc->pool = ((char *)tc + TC_HDR_SIZE + TALLOC_POOL_HDR_SIZE);
1077 #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
1078 VALGRIND_MAKE_MEM_NOACCESS(
1079 tc->pool, tc->size - TALLOC_POOL_HDR_SIZE);
1080 #endif
1081 }
1082 }
1083
1084 /*
1085 Allocate a bit of memory as a child of an existing pointer
1086 */
1087 void *_talloc(const void *context, size_t size)
1088 {
1089 return __talloc(context, size);
1090 }
1091
1092 /*
1093 externally callable talloc_set_name_const()
1094 */
1095 void talloc_set_name_const(const void *ptr, const char *name)
1096 {
1097 _talloc_set_name_const(ptr, name);
1098 }
1099
1100 /*
1101 create a named talloc pointer. Any talloc pointer can be named, and
1102 talloc_named() operates just like talloc() except that it allows you
1103 to name the pointer.
1104 */
1105 void *talloc_named_const(const void *context, size_t size, const char *name)
1106 {
1107 return _talloc_named_const(context, size, name);
1108 }
1109
1110 /*
1111 free a talloc pointer. This also frees all child pointers of this
1112 pointer recursively
1113
1114 return 0 if the memory is actually freed, otherwise -1. The memory
1115 will not be freed if the ref_count is > 1 or the destructor (if
1116 any) returns non-zero
1117 */
1118 int _talloc_free(void *ptr, const char *location)
1119 {
1120 struct talloc_chunk *tc;
1121
1122 if (unlikely(ptr == NULL)) {
1123 return -1;
1124 }
1125
1126 tc = talloc_chunk_from_ptr(ptr);
1127
1128 if (unlikely(tc->refs != NULL)) {
1129 struct talloc_reference_handle *h;
1130
1131 talloc_log("ERROR: talloc_free with references at %s\n",
1132 location);
1133
1134 for (h=tc->refs; h; h=h->next) {
1135 talloc_log("\treference at %s\n",
1136 h->location);
1137 }
1138 return -1;
1139 }
1140
1141 return _talloc_free_internal(ptr, location);
1142 }
1143
1144
1145 static INLINE size_t min_size(size_t a, size_t b)
1146 {
1147 return a > b ? b : a;
1148 }
1149
1150 /*
1151 A talloc version of realloc. The context argument is only used if
1152 ptr is NULL
1153 */
1154 void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n ame)
1155 {
1156 struct talloc_chunk *tc;
1157 void *new_ptr;
1158 int malloced = 0;
1159
1160 /* size zero is equivalent to free() */
1161 if (unlikely(size == 0)) {
1162 talloc_unlink(context, ptr);
1163 return NULL;
1164 }
1165
1166 if (unlikely(size >= MAX_TALLOC_SIZE)) {
1167 return NULL;
1168 }
1169
1170 /* realloc(NULL) is equivalent to malloc() */
1171 if (ptr == NULL) {
1172 return _talloc_named_const(context, size, name);
1173 }
1174
1175 tc = talloc_chunk_from_ptr(ptr);
1176
1177 /* don't allow realloc on referenced pointers */
1178 if (unlikely(tc->refs)) {
1179 return NULL;
1180 }
1181
1182 /* don't let anybody try to realloc a talloc_pool */
1183 if (unlikely(tc->flags & TALLOC_FLAG_POOL)) {
1184 return NULL;
1185 }
1186
1187 /* don't shrink if we have less than 1k to gain */
1188 if ((size < tc->size) && ((tc->size - size) < 1024)) {
1189 tc->size = size;
1190 return ptr;
1191 }
1192
1193 /* by resetting magic we catch users of the old memory */
1194 tc->flags |= TALLOC_FLAG_FREE;
1195
1196 #if ALWAYS_REALLOC
1197 new_ptr = malloc(size + TC_HDR_SIZE);
1198 if (new_ptr) {
1199 memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE);
1200 free(tc);
1201 }
1202 #else
1203 if (tc->flags & TALLOC_FLAG_POOLMEM) {
1204
1205 new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE);
1206 *talloc_pool_objectcount((struct talloc_chunk *)
1207 (tc->pool)) -= 1;
1208
1209 if (new_ptr == NULL) {
1210 new_ptr = malloc(TC_HDR_SIZE+size);
1211 malloced = 1;
1212 }
1213
1214 if (new_ptr) {
1215 memcpy(new_ptr, tc, min_size(tc->size,size) + TC_HDR_SIZ E);
1216 }
1217 }
1218 else {
1219 new_ptr = realloc(tc, size + TC_HDR_SIZE);
1220 }
1221 #endif
1222 if (unlikely(!new_ptr)) {
1223 tc->flags &= ~TALLOC_FLAG_FREE;
1224 return NULL;
1225 }
1226
1227 tc = (struct talloc_chunk *)new_ptr;
1228 tc->flags &= ~TALLOC_FLAG_FREE;
1229 if (malloced) {
1230 tc->flags &= ~TALLOC_FLAG_POOLMEM;
1231 }
1232 if (tc->parent) {
1233 tc->parent->child = tc;
1234 }
1235 if (tc->child) {
1236 tc->child->parent = tc;
1237 }
1238
1239 if (tc->prev) {
1240 tc->prev->next = tc;
1241 }
1242 if (tc->next) {
1243 tc->next->prev = tc;
1244 }
1245
1246 tc->size = size;
1247 _talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
1248
1249 return TC_PTR_FROM_CHUNK(tc);
1250 }
1251
1252 /*
1253 a wrapper around talloc_steal() for situations where you are moving a pointer
1254 between two structures, and want the old pointer to be set to NULL
1255 */
1256 void *_talloc_move(const void *new_ctx, const void *_pptr)
1257 {
1258 const void **pptr = discard_const_p(const void *,_pptr);
1259 void *ret = talloc_steal(new_ctx, discard_const_p(void, *pptr));
1260 (*pptr) = NULL;
1261 return ret;
1262 }
1263
1264 /*
1265 return the total size of a talloc pool (subtree)
1266 */
1267 size_t talloc_total_size(const void *ptr)
1268 {
1269 size_t total = 0;
1270 struct talloc_chunk *c, *tc;
1271
1272 if (ptr == NULL) {
1273 ptr = null_context;
1274 }
1275 if (ptr == NULL) {
1276 return 0;
1277 }
1278
1279 tc = talloc_chunk_from_ptr(ptr);
1280
1281 if (tc->flags & TALLOC_FLAG_LOOP) {
1282 return 0;
1283 }
1284
1285 tc->flags |= TALLOC_FLAG_LOOP;
1286
1287 if (likely(tc->name != TALLOC_MAGIC_REFERENCE)) {
1288 total = tc->size;
1289 }
1290 for (c=tc->child;c;c=c->next) {
1291 total += talloc_total_size(TC_PTR_FROM_CHUNK(c));
1292 }
1293
1294 tc->flags &= ~TALLOC_FLAG_LOOP;
1295
1296 return total;
1297 }
1298
1299 /*
1300 return the total number of blocks in a talloc pool (subtree)
1301 */
1302 size_t talloc_total_blocks(const void *ptr)
1303 {
1304 size_t total = 0;
1305 struct talloc_chunk *c, *tc;
1306
1307 if (ptr == NULL) {
1308 ptr = null_context;
1309 }
1310 if (ptr == NULL) {
1311 return 0;
1312 }
1313
1314 tc = talloc_chunk_from_ptr(ptr);
1315
1316 if (tc->flags & TALLOC_FLAG_LOOP) {
1317 return 0;
1318 }
1319
1320 tc->flags |= TALLOC_FLAG_LOOP;
1321
1322 total++;
1323 for (c=tc->child;c;c=c->next) {
1324 total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c));
1325 }
1326
1327 tc->flags &= ~TALLOC_FLAG_LOOP;
1328
1329 return total;
1330 }
1331
1332 /*
1333 return the number of external references to a pointer
1334 */
1335 size_t talloc_reference_count(const void *ptr)
1336 {
1337 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
1338 struct talloc_reference_handle *h;
1339 size_t ret = 0;
1340
1341 for (h=tc->refs;h;h=h->next) {
1342 ret++;
1343 }
1344 return ret;
1345 }
1346
1347 /*
1348 report on memory usage by all children of a pointer, giving a full tree view
1349 */
1350 void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
1351 void (*callback)(const void *ptr,
1352 int depth, int max_depth,
1353 int is_ref,
1354 void *private_data),
1355 void *private_data)
1356 {
1357 struct talloc_chunk *c, *tc;
1358
1359 if (ptr == NULL) {
1360 ptr = null_context;
1361 }
1362 if (ptr == NULL) return;
1363
1364 tc = talloc_chunk_from_ptr(ptr);
1365
1366 if (tc->flags & TALLOC_FLAG_LOOP) {
1367 return;
1368 }
1369
1370 callback(ptr, depth, max_depth, 0, private_data);
1371
1372 if (max_depth >= 0 && depth >= max_depth) {
1373 return;
1374 }
1375
1376 tc->flags |= TALLOC_FLAG_LOOP;
1377 for (c=tc->child;c;c=c->next) {
1378 if (c->name == TALLOC_MAGIC_REFERENCE) {
1379 struct talloc_reference_handle *h = (struct talloc_refer ence_handle *)TC_PTR_FROM_CHUNK(c);
1380 callback(h->ptr, depth + 1, max_depth, 1, private_data);
1381 } else {
1382 talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1, max_depth, callback, private_data);
1383 }
1384 }
1385 tc->flags &= ~TALLOC_FLAG_LOOP;
1386 }
1387
1388 static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_ depth, int is_ref, void *_f)
1389 {
1390 const char *name = talloc_get_name(ptr);
1391 FILE *f = (FILE *)_f;
1392
1393 if (is_ref) {
1394 fprintf(f, "%*sreference to: %s\n", depth*4, "", name);
1395 return;
1396 }
1397
1398 if (depth == 0) {
1399 fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blo cks)\n",
1400 (max_depth < 0 ? "full " :""), name,
1401 (unsigned long)talloc_total_size(ptr),
1402 (unsigned long)talloc_total_blocks(ptr));
1403 return;
1404 }
1405
1406 fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n",
1407 depth*4, "",
1408 name,
1409 (unsigned long)talloc_total_size(ptr),
1410 (unsigned long)talloc_total_blocks(ptr),
1411 (int)talloc_reference_count(ptr), ptr);
1412
1413 #if 0
1414 fprintf(f, "content: ");
1415 if (talloc_total_size(ptr)) {
1416 int tot = talloc_total_size(ptr);
1417 int i;
1418
1419 for (i = 0; i < tot; i++) {
1420 if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126)) {
1421 fprintf(f, "%c", ((char *)ptr)[i]);
1422 } else {
1423 fprintf(f, "~%02x", ((char *)ptr)[i]);
1424 }
1425 }
1426 }
1427 fprintf(f, "\n");
1428 #endif
1429 }
1430
1431 /*
1432 report on memory usage by all children of a pointer, giving a full tree view
1433 */
1434 void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f )
1435 {
1436 if (f) {
1437 talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_dept h_FILE_helper, f);
1438 fflush(f);
1439 }
1440 }
1441
1442 /*
1443 report on memory usage by all children of a pointer, giving a full tree view
1444 */
1445 void talloc_report_full(const void *ptr, FILE *f)
1446 {
1447 talloc_report_depth_file(ptr, 0, -1, f);
1448 }
1449
1450 /*
1451 report on memory usage by all children of a pointer
1452 */
1453 void talloc_report(const void *ptr, FILE *f)
1454 {
1455 talloc_report_depth_file(ptr, 0, 1, f);
1456 }
1457
1458 /*
1459 report on any memory hanging off the null context
1460 */
1461 static void talloc_report_null(void)
1462 {
1463 if (talloc_total_size(null_context) != 0) {
1464 talloc_report(null_context, stderr);
1465 }
1466 }
1467
1468 /*
1469 report on any memory hanging off the null context
1470 */
1471 static void talloc_report_null_full(void)
1472 {
1473 if (talloc_total_size(null_context) != 0) {
1474 talloc_report_full(null_context, stderr);
1475 }
1476 }
1477
1478 /*
1479 enable tracking of the NULL context
1480 */
1481 void talloc_enable_null_tracking(void)
1482 {
1483 if (null_context == NULL) {
1484 null_context = _talloc_named_const(NULL, 0, "null_context");
1485 if (autofree_context != NULL) {
1486 talloc_reparent(NULL, null_context, autofree_context);
1487 }
1488 }
1489 }
1490
1491 /*
1492 enable tracking of the NULL context, not moving the autofree context
1493 into the NULL context. This is needed for the talloc testsuite
1494 */
1495 void talloc_enable_null_tracking_no_autofree(void)
1496 {
1497 if (null_context == NULL) {
1498 null_context = _talloc_named_const(NULL, 0, "null_context");
1499 }
1500 }
1501
1502 /*
1503 disable tracking of the NULL context
1504 */
1505 void talloc_disable_null_tracking(void)
1506 {
1507 if (null_context != NULL) {
1508 /* we have to move any children onto the real NULL
1509 context */
1510 struct talloc_chunk *tc, *tc2;
1511 tc = talloc_chunk_from_ptr(null_context);
1512 for (tc2 = tc->child; tc2; tc2=tc2->next) {
1513 if (tc2->parent == tc) tc2->parent = NULL;
1514 if (tc2->prev == tc) tc2->prev = NULL;
1515 }
1516 for (tc2 = tc->next; tc2; tc2=tc2->next) {
1517 if (tc2->parent == tc) tc2->parent = NULL;
1518 if (tc2->prev == tc) tc2->prev = NULL;
1519 }
1520 tc->child = NULL;
1521 tc->next = NULL;
1522 }
1523 talloc_free(null_context);
1524 null_context = NULL;
1525 }
1526
1527 /*
1528 enable leak reporting on exit
1529 */
1530 void talloc_enable_leak_report(void)
1531 {
1532 talloc_enable_null_tracking();
1533 atexit(talloc_report_null);
1534 }
1535
1536 /*
1537 enable full leak reporting on exit
1538 */
1539 void talloc_enable_leak_report_full(void)
1540 {
1541 talloc_enable_null_tracking();
1542 atexit(talloc_report_null_full);
1543 }
1544
1545 /*
1546 talloc and zero memory.
1547 */
1548 void *_talloc_zero(const void *ctx, size_t size, const char *name)
1549 {
1550 void *p = _talloc_named_const(ctx, size, name);
1551
1552 if (p) {
1553 memset(p, '\0', size);
1554 }
1555
1556 return p;
1557 }
1558
1559 /*
1560 memdup with a talloc.
1561 */
1562 void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name )
1563 {
1564 void *newp = _talloc_named_const(t, size, name);
1565
1566 if (likely(newp)) {
1567 memcpy(newp, p, size);
1568 }
1569
1570 return newp;
1571 }
1572
1573 static INLINE char *__talloc_strlendup(const void *t, const char *p, size_t len)
1574 {
1575 char *ret;
1576
1577 ret = (char *)__talloc(t, len + 1);
1578 if (unlikely(!ret)) return NULL;
1579
1580 memcpy(ret, p, len);
1581 ret[len] = 0;
1582
1583 _talloc_set_name_const(ret, ret);
1584 return ret;
1585 }
1586
1587 /*
1588 strdup with a talloc
1589 */
1590 char *talloc_strdup(const void *t, const char *p)
1591 {
1592 if (unlikely(!p)) return NULL;
1593 return __talloc_strlendup(t, p, strlen(p));
1594 }
1595
1596 #ifndef HAVE_STRNLEN
1597 #define strnlen rep_strnlen
1598 static size_t rep_strnlen(const char* s, size_t n)
1599 {
1600 if (unlikely(!s)) return 0;
1601 int i = 0;
1602 while (i < n && *s++ != '\0')
1603 ++i;
1604 return i;
1605 }
1606 #endif
1607
1608 /*
1609 strndup with a talloc
1610 */
1611 char *talloc_strndup(const void *t, const char *p, size_t n)
1612 {
1613 if (unlikely(!p)) return NULL;
1614 return __talloc_strlendup(t, p, strnlen(p, n));
1615 }
1616
1617 static INLINE char *__talloc_strlendup_append(char *s, size_t slen,
1618 const char *a, size_t alen)
1619 {
1620 char *ret;
1621
1622 ret = talloc_realloc(NULL, s, char, slen + alen + 1);
1623 if (unlikely(!ret)) return NULL;
1624
1625 /* append the string and the trailing \0 */
1626 memcpy(&ret[slen], a, alen);
1627 ret[slen+alen] = 0;
1628
1629 _talloc_set_name_const(ret, ret);
1630 return ret;
1631 }
1632
1633 /*
1634 * Appends at the end of the string.
1635 */
1636 char *talloc_strdup_append(char *s, const char *a)
1637 {
1638 if (unlikely(!s)) {
1639 return talloc_strdup(NULL, a);
1640 }
1641
1642 if (unlikely(!a)) {
1643 return s;
1644 }
1645
1646 return __talloc_strlendup_append(s, strlen(s), a, strlen(a));
1647 }
1648
1649 /*
1650 * Appends at the end of the talloc'ed buffer,
1651 * not the end of the string.
1652 */
1653 char *talloc_strdup_append_buffer(char *s, const char *a)
1654 {
1655 size_t slen;
1656
1657 if (unlikely(!s)) {
1658 return talloc_strdup(NULL, a);
1659 }
1660
1661 if (unlikely(!a)) {
1662 return s;
1663 }
1664
1665 slen = talloc_get_size(s);
1666 if (likely(slen > 0)) {
1667 slen--;
1668 }
1669
1670 return __talloc_strlendup_append(s, slen, a, strlen(a));
1671 }
1672
1673 /*
1674 * Appends at the end of the string.
1675 */
1676 char *talloc_strndup_append(char *s, const char *a, size_t n)
1677 {
1678 if (unlikely(!s)) {
1679 return talloc_strdup(NULL, a);
1680 }
1681
1682 if (unlikely(!a)) {
1683 return s;
1684 }
1685
1686 return __talloc_strlendup_append(s, strlen(s), a, strnlen(a, n));
1687 }
1688
1689 /*
1690 * Appends at the end of the talloc'ed buffer,
1691 * not the end of the string.
1692 */
1693 char *talloc_strndup_append_buffer(char *s, const char *a, size_t n)
1694 {
1695 size_t slen;
1696
1697 if (unlikely(!s)) {
1698 return talloc_strdup(NULL, a);
1699 }
1700
1701 if (unlikely(!a)) {
1702 return s;
1703 }
1704
1705 slen = talloc_get_size(s);
1706 if (likely(slen > 0)) {
1707 slen--;
1708 }
1709
1710 return __talloc_strlendup_append(s, slen, a, strnlen(a, n));
1711 }
1712
1713 #ifndef HAVE_VA_COPY
1714 #ifdef HAVE___VA_COPY
1715 #define va_copy(dest, src) __va_copy(dest, src)
1716 #else
1717 #define va_copy(dest, src) (dest) = (src)
1718 #endif
1719 #endif
1720
1721 char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
1722 {
1723 int len;
1724 char *ret;
1725 va_list ap2;
1726
1727 va_copy(ap2, ap);
1728 len = vsnprintf(NULL, 0, fmt, ap2);
1729 va_end(ap2);
1730 if (unlikely(len < 0)) {
1731 return NULL;
1732 }
1733
1734 ret = (char *)__talloc(t, len+1);
1735 if (unlikely(!ret)) return NULL;
1736
1737 va_copy(ap2, ap);
1738 vsnprintf(ret, len+1, fmt, ap2);
1739 va_end(ap2);
1740
1741 _talloc_set_name_const(ret, ret);
1742 return ret;
1743 }
1744
1745
1746 /*
1747 Perform string formatting, and return a pointer to newly allocated
1748 memory holding the result, inside a memory pool.
1749 */
1750 char *talloc_asprintf(const void *t, const char *fmt, ...)
1751 {
1752 va_list ap;
1753 char *ret;
1754
1755 va_start(ap, fmt);
1756 ret = talloc_vasprintf(t, fmt, ap);
1757 va_end(ap);
1758 return ret;
1759 }
1760
1761 static INLINE char *__talloc_vaslenprintf_append(char *s, size_t slen,
1762 const char *fmt, va_list ap)
1763 PRINTF_ATTRIBUTE(3,0);
1764
1765 static INLINE char *__talloc_vaslenprintf_append(char *s, size_t slen,
1766 const char *fmt, va_list ap)
1767 {
1768 /* ssize_t isn't present on Windows. */
1769 #ifndef _MSC_VER
1770 ssize_t alen;
1771 #else
1772 size_t alen;
1773 #endif
1774 va_list ap2;
1775
1776 va_copy(ap2, ap);
1777 alen = vsnprintf(NULL, 0, fmt, ap2);
1778 va_end(ap2);
1779
1780 if (alen <= 0) {
1781 /* Either the vsnprintf failed or the format resulted in
1782 * no characters being formatted. In the former case, we
1783 * ought to return NULL, in the latter we ought to return
1784 * the original string. Most current callers of this
1785 * function expect it to never return NULL.
1786 */
1787 return s;
1788 }
1789
1790 s = talloc_realloc(NULL, s, char, slen + alen + 1);
1791 if (!s) return NULL;
1792
1793 va_copy(ap2, ap);
1794 vsnprintf(s + slen, alen + 1, fmt, ap2);
1795 va_end(ap2);
1796
1797 _talloc_set_name_const(s, s);
1798 return s;
1799 }
1800
1801 /**
1802 * Realloc @p s to append the formatted result of @p fmt and @p ap,
1803 * and return @p s, which may have moved. Good for gradually
1804 * accumulating output into a string buffer. Appends at the end
1805 * of the string.
1806 **/
1807 char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
1808 {
1809 if (unlikely(!s)) {
1810 return talloc_vasprintf(NULL, fmt, ap);
1811 }
1812
1813 return __talloc_vaslenprintf_append(s, strlen(s), fmt, ap);
1814 }
1815
1816 /**
1817 * Realloc @p s to append the formatted result of @p fmt and @p ap,
1818 * and return @p s, which may have moved. Always appends at the
1819 * end of the talloc'ed buffer, not the end of the string.
1820 **/
1821 char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap)
1822 {
1823 size_t slen;
1824
1825 if (unlikely(!s)) {
1826 return talloc_vasprintf(NULL, fmt, ap);
1827 }
1828
1829 slen = talloc_get_size(s);
1830 if (likely(slen > 0)) {
1831 slen--;
1832 }
1833
1834 return __talloc_vaslenprintf_append(s, slen, fmt, ap);
1835 }
1836
1837 /*
1838 Realloc @p s to append the formatted result of @p fmt and return @p
1839 s, which may have moved. Good for gradually accumulating output
1840 into a string buffer.
1841 */
1842 char *talloc_asprintf_append(char *s, const char *fmt, ...)
1843 {
1844 va_list ap;
1845
1846 va_start(ap, fmt);
1847 s = talloc_vasprintf_append(s, fmt, ap);
1848 va_end(ap);
1849 return s;
1850 }
1851
1852 /*
1853 Realloc @p s to append the formatted result of @p fmt and return @p
1854 s, which may have moved. Good for gradually accumulating output
1855 into a buffer.
1856 */
1857 char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...)
1858 {
1859 va_list ap;
1860
1861 va_start(ap, fmt);
1862 s = talloc_vasprintf_append_buffer(s, fmt, ap);
1863 va_end(ap);
1864 return s;
1865 }
1866
1867 /*
1868 alloc an array, checking for integer overflow in the array size
1869 */
1870 void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
1871 {
1872 if (count >= MAX_TALLOC_SIZE/el_size) {
1873 return NULL;
1874 }
1875 return _talloc_named_const(ctx, el_size * count, name);
1876 }
1877
1878 /*
1879 alloc an zero array, checking for integer overflow in the array size
1880 */
1881 void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name)
1882 {
1883 if (count >= MAX_TALLOC_SIZE/el_size) {
1884 return NULL;
1885 }
1886 return _talloc_zero(ctx, el_size * count, name);
1887 }
1888
1889 /*
1890 realloc an array, checking for integer overflow in the array size
1891 */
1892 void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
1893 {
1894 if (count >= MAX_TALLOC_SIZE/el_size) {
1895 return NULL;
1896 }
1897 return _talloc_realloc(ctx, ptr, el_size * count, name);
1898 }
1899
1900 /*
1901 a function version of talloc_realloc(), so it can be passed as a function poin ter
1902 to libraries that want a realloc function (a realloc function encapsulates
1903 all the basic capabilities of an allocation library, which is why this is usef ul)
1904 */
1905 void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
1906 {
1907 return _talloc_realloc(context, ptr, size, NULL);
1908 }
1909
1910
1911 static int talloc_autofree_destructor(void *ptr)
1912 {
1913 autofree_context = NULL;
1914 return 0;
1915 }
1916
1917 static void talloc_autofree(void)
1918 {
1919 talloc_free(autofree_context);
1920 }
1921
1922 /*
1923 return a context which will be auto-freed on exit
1924 this is useful for reducing the noise in leak reports
1925 */
1926 void *talloc_autofree_context(void)
1927 {
1928 if (autofree_context == NULL) {
1929 autofree_context = _talloc_named_const(NULL, 0, "autofree_contex t");
1930 talloc_set_destructor(autofree_context, talloc_autofree_destruct or);
1931 atexit(talloc_autofree);
1932 }
1933 return autofree_context;
1934 }
1935
1936 size_t talloc_get_size(const void *context)
1937 {
1938 struct talloc_chunk *tc;
1939
1940 if (context == NULL) {
1941 context = null_context;
1942 }
1943 if (context == NULL) {
1944 return 0;
1945 }
1946
1947 tc = talloc_chunk_from_ptr(context);
1948
1949 return tc->size;
1950 }
1951
1952 /*
1953 find a parent of this context that has the given name, if any
1954 */
1955 void *talloc_find_parent_byname(const void *context, const char *name)
1956 {
1957 struct talloc_chunk *tc;
1958
1959 if (context == NULL) {
1960 return NULL;
1961 }
1962
1963 tc = talloc_chunk_from_ptr(context);
1964 while (tc) {
1965 if (tc->name && strcmp(tc->name, name) == 0) {
1966 return TC_PTR_FROM_CHUNK(tc);
1967 }
1968 while (tc && tc->prev) tc = tc->prev;
1969 if (tc) {
1970 tc = tc->parent;
1971 }
1972 }
1973 return NULL;
1974 }
1975
1976 /*
1977 show the parentage of a context
1978 */
1979 void talloc_show_parents(const void *context, FILE *file)
1980 {
1981 struct talloc_chunk *tc;
1982
1983 if (context == NULL) {
1984 fprintf(file, "talloc no parents for NULL\n");
1985 return;
1986 }
1987
1988 tc = talloc_chunk_from_ptr(context);
1989 fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
1990 while (tc) {
1991 fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)) );
1992 while (tc && tc->prev) tc = tc->prev;
1993 if (tc) {
1994 tc = tc->parent;
1995 }
1996 }
1997 fflush(file);
1998 }
1999
2000 /*
2001 return 1 if ptr is a parent of context
2002 */
2003 int talloc_is_parent(const void *context, const void *ptr)
2004 {
2005 struct talloc_chunk *tc;
2006
2007 if (context == NULL) {
2008 return 0;
2009 }
2010
2011 tc = talloc_chunk_from_ptr(context);
2012 while (tc) {
2013 if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1;
2014 while (tc && tc->prev) tc = tc->prev;
2015 if (tc) {
2016 tc = tc->parent;
2017 }
2018 }
2019 return 0;
2020 }
OLDNEW
« no previous file with comments | « third_party/talloc/talloc.h ('k') | third_party/talloc/talloc.exports » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698