00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #ifdef _SAMBA_BUILD_
00035 #include "version.h"
00036 #if (SAMBA_VERSION_MAJOR<4)
00037 #include "includes.h"
00038
00039
00040 #ifdef malloc
00041 #undef malloc
00042 #endif
00043 #ifdef realloc
00044 #undef realloc
00045 #endif
00046 #define _TALLOC_SAMBA3
00047 #endif
00048 #endif
00049
00050 #ifndef _TALLOC_SAMBA3
00051 #include "replace.h"
00052 #include "talloc.h"
00053 #endif
00054
00055
00056
00057 #define ALWAYS_REALLOC 0
00058
00059
00060 #define MAX_TALLOC_SIZE 0x10000000
00061 #define TALLOC_MAGIC 0xe814ec70
00062 #define TALLOC_FLAG_FREE 0x01
00063 #define TALLOC_FLAG_LOOP 0x02
00064 #define TALLOC_MAGIC_REFERENCE ((const char *)1)
00065
00066
00067
00068 #ifndef TALLOC_ABORT
00069 #define TALLOC_ABORT(reason) abort()
00070 #endif
00071
00072 #ifndef discard_const_p
00073 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
00074 # define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
00075 #else
00076 # define discard_const_p(type, ptr) ((type *)(ptr))
00077 #endif
00078 #endif
00079
00080
00081 #if (__GNUC__ >= 3)
00082
00083
00084 #define likely(x) __builtin_expect(!!(x), 1)
00085 #define unlikely(x) __builtin_expect(!!(x), 0)
00086 #else
00087 #define likely(x) x
00088 #define unlikely(x) x
00089 #endif
00090
00091
00092
00093
00094
00095 static void *null_context;
00096 static void *autofree_context;
00097
00098 struct talloc_reference_handle {
00099 struct talloc_reference_handle *next, *prev;
00100 void *ptr;
00101 };
00102
00103 typedef int (*talloc_destructor_t)(void *);
00104
00105 struct talloc_chunk {
00106 struct talloc_chunk *next, *prev;
00107 struct talloc_chunk *parent, *child;
00108 struct talloc_reference_handle *refs;
00109 talloc_destructor_t destructor;
00110 const char *name;
00111 size_t size;
00112 unsigned flags;
00113 };
00114
00115
00116 #define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15)
00117 #define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc))
00118
00119
00120 static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
00121 {
00122 const char *pp = (const char *)ptr;
00123 struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE);
00124 if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) {
00125 if (tc->flags & TALLOC_FLAG_FREE) {
00126 TALLOC_ABORT("Bad talloc magic value - double free");
00127 } else {
00128 TALLOC_ABORT("Bad talloc magic value - unknown value");
00129 }
00130 }
00131 return tc;
00132 }
00133
00134
00135 #define _TLIST_ADD(list, p) \
00136 do { \
00137 if (!(list)) { \
00138 (list) = (p); \
00139 (p)->next = (p)->prev = NULL; \
00140 } else { \
00141 (list)->prev = (p); \
00142 (p)->next = (list); \
00143 (p)->prev = NULL; \
00144 (list) = (p); \
00145 }\
00146 } while (0)
00147
00148
00149 #define _TLIST_REMOVE(list, p) \
00150 do { \
00151 if ((p) == (list)) { \
00152 (list) = (p)->next; \
00153 if (list) (list)->prev = NULL; \
00154 } else { \
00155 if ((p)->prev) (p)->prev->next = (p)->next; \
00156 if ((p)->next) (p)->next->prev = (p)->prev; \
00157 } \
00158 if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
00159 } while (0)
00160
00161
00162
00163
00164
00165 static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr)
00166 {
00167 struct talloc_chunk *tc;
00168
00169 if (unlikely(ptr == NULL)) {
00170 return NULL;
00171 }
00172
00173 tc = talloc_chunk_from_ptr(ptr);
00174 while (tc->prev) tc=tc->prev;
00175
00176 return tc->parent;
00177 }
00178
00179 void *talloc_parent(const void *ptr)
00180 {
00181 struct talloc_chunk *tc = talloc_parent_chunk(ptr);
00182 return tc? TC_PTR_FROM_CHUNK(tc) : NULL;
00183 }
00184
00185
00186
00187
00188 const char *talloc_parent_name(const void *ptr)
00189 {
00190 struct talloc_chunk *tc = talloc_parent_chunk(ptr);
00191 return tc? tc->name : NULL;
00192 }
00193
00194
00195
00196
00197 static inline void *__talloc(const void *context, size_t size)
00198 {
00199 struct talloc_chunk *tc;
00200
00201 if (unlikely(context == NULL)) {
00202 context = null_context;
00203 }
00204
00205 if (unlikely(size >= MAX_TALLOC_SIZE)) {
00206 return NULL;
00207 }
00208
00209 tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size);
00210 if (unlikely(tc == NULL)) return NULL;
00211
00212 tc->size = size;
00213 tc->flags = TALLOC_MAGIC;
00214 tc->destructor = NULL;
00215 tc->child = NULL;
00216 tc->name = NULL;
00217 tc->refs = NULL;
00218
00219 if (likely(context)) {
00220 struct talloc_chunk *parent = talloc_chunk_from_ptr(context);
00221
00222 if (parent->child) {
00223 parent->child->parent = NULL;
00224 tc->next = parent->child;
00225 tc->next->prev = tc;
00226 } else {
00227 tc->next = NULL;
00228 }
00229 tc->parent = parent;
00230 tc->prev = NULL;
00231 parent->child = tc;
00232 } else {
00233 tc->next = tc->prev = tc->parent = NULL;
00234 }
00235
00236 return TC_PTR_FROM_CHUNK(tc);
00237 }
00238
00239
00240
00241
00242
00243
00244
00245 void _talloc_set_destructor(const void *ptr, int (*destructor)(void *))
00246 {
00247 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
00248 tc->destructor = destructor;
00249 }
00250
00251
00252
00253
00254 int talloc_increase_ref_count(const void *ptr)
00255 {
00256 if (unlikely(!talloc_reference(null_context, ptr))) {
00257 return -1;
00258 }
00259 return 0;
00260 }
00261
00262
00263
00264
00265
00266
00267 static int talloc_reference_destructor(struct talloc_reference_handle *handle)
00268 {
00269 struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr);
00270 _TLIST_REMOVE(ptr_tc->refs, handle);
00271 return 0;
00272 }
00273
00274
00275
00276
00277
00278 static inline void _talloc_set_name_const(const void *ptr, const char *name)
00279 {
00280 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
00281 tc->name = name;
00282 }
00283
00284
00285
00286
00287 static inline void *_talloc_named_const(const void *context, size_t size, const char *name)
00288 {
00289 void *ptr;
00290
00291 ptr = __talloc(context, size);
00292 if (unlikely(ptr == NULL)) {
00293 return NULL;
00294 }
00295
00296 _talloc_set_name_const(ptr, name);
00297
00298 return ptr;
00299 }
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310 void *_talloc_reference(const void *context, const void *ptr)
00311 {
00312 struct talloc_chunk *tc;
00313 struct talloc_reference_handle *handle;
00314 if (unlikely(ptr == NULL)) return NULL;
00315
00316 tc = talloc_chunk_from_ptr(ptr);
00317 handle = (struct talloc_reference_handle *)_talloc_named_const(context,
00318 sizeof(struct talloc_reference_handle),
00319 TALLOC_MAGIC_REFERENCE);
00320 if (unlikely(handle == NULL)) return NULL;
00321
00322
00323
00324
00325 talloc_set_destructor(handle, talloc_reference_destructor);
00326 handle->ptr = discard_const_p(void, ptr);
00327 _TLIST_ADD(tc->refs, handle);
00328 return handle->ptr;
00329 }
00330
00331
00332
00333
00334
00335 static inline int _talloc_free(void *ptr)
00336 {
00337 struct talloc_chunk *tc;
00338
00339 if (unlikely(ptr == NULL)) {
00340 return -1;
00341 }
00342
00343 tc = talloc_chunk_from_ptr(ptr);
00344
00345 if (unlikely(tc->refs)) {
00346 int is_child;
00347
00348
00349
00350
00351
00352
00353
00354 is_child = talloc_is_parent(tc->refs, ptr);
00355 _talloc_free(tc->refs);
00356 if (is_child) {
00357 return _talloc_free(ptr);
00358 }
00359 return -1;
00360 }
00361
00362 if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) {
00363
00364 return 0;
00365 }
00366
00367 if (unlikely(tc->destructor)) {
00368 talloc_destructor_t d = tc->destructor;
00369 if (d == (talloc_destructor_t)-1) {
00370 return -1;
00371 }
00372 tc->destructor = (talloc_destructor_t)-1;
00373 if (d(ptr) == -1) {
00374 tc->destructor = d;
00375 return -1;
00376 }
00377 tc->destructor = NULL;
00378 }
00379
00380 if (tc->parent) {
00381 _TLIST_REMOVE(tc->parent->child, tc);
00382 if (tc->parent->child) {
00383 tc->parent->child->parent = tc->parent;
00384 }
00385 } else {
00386 if (tc->prev) tc->prev->next = tc->next;
00387 if (tc->next) tc->next->prev = tc->prev;
00388 }
00389
00390 tc->flags |= TALLOC_FLAG_LOOP;
00391
00392 while (tc->child) {
00393
00394
00395
00396
00397
00398 void *child = TC_PTR_FROM_CHUNK(tc->child);
00399 const void *new_parent = null_context;
00400 if (unlikely(tc->child->refs)) {
00401 struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
00402 if (p) new_parent = TC_PTR_FROM_CHUNK(p);
00403 }
00404 if (unlikely(_talloc_free(child) == -1)) {
00405 if (new_parent == null_context) {
00406 struct talloc_chunk *p = talloc_parent_chunk(ptr);
00407 if (p) new_parent = TC_PTR_FROM_CHUNK(p);
00408 }
00409 talloc_steal(new_parent, child);
00410 }
00411 }
00412
00413 tc->flags |= TALLOC_FLAG_FREE;
00414 free(tc);
00415 return 0;
00416 }
00417
00418
00419
00420
00421
00422
00423 void *_talloc_steal(const void *new_ctx, const void *ptr)
00424 {
00425 struct talloc_chunk *tc, *new_tc;
00426
00427 if (unlikely(!ptr)) {
00428 return NULL;
00429 }
00430
00431 if (unlikely(new_ctx == NULL)) {
00432 new_ctx = null_context;
00433 }
00434
00435 tc = talloc_chunk_from_ptr(ptr);
00436
00437 if (unlikely(new_ctx == NULL)) {
00438 if (tc->parent) {
00439 _TLIST_REMOVE(tc->parent->child, tc);
00440 if (tc->parent->child) {
00441 tc->parent->child->parent = tc->parent;
00442 }
00443 } else {
00444 if (tc->prev) tc->prev->next = tc->next;
00445 if (tc->next) tc->next->prev = tc->prev;
00446 }
00447
00448 tc->parent = tc->next = tc->prev = NULL;
00449 return discard_const_p(void, ptr);
00450 }
00451
00452 new_tc = talloc_chunk_from_ptr(new_ctx);
00453
00454 if (unlikely(tc == new_tc || tc->parent == new_tc)) {
00455 return discard_const_p(void, ptr);
00456 }
00457
00458 if (tc->parent) {
00459 _TLIST_REMOVE(tc->parent->child, tc);
00460 if (tc->parent->child) {
00461 tc->parent->child->parent = tc->parent;
00462 }
00463 } else {
00464 if (tc->prev) tc->prev->next = tc->next;
00465 if (tc->next) tc->next->prev = tc->prev;
00466 }
00467
00468 tc->parent = new_tc;
00469 if (new_tc->child) new_tc->child->parent = NULL;
00470 _TLIST_ADD(new_tc->child, tc);
00471
00472 return discard_const_p(void, ptr);
00473 }
00474
00475
00476
00477
00478
00479
00480
00481
00482 static inline int talloc_unreference(const void *context, const void *ptr)
00483 {
00484 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
00485 struct talloc_reference_handle *h;
00486
00487 if (unlikely(context == NULL)) {
00488 context = null_context;
00489 }
00490
00491 for (h=tc->refs;h;h=h->next) {
00492 struct talloc_chunk *p = talloc_parent_chunk(h);
00493 if (p == NULL) {
00494 if (context == NULL) break;
00495 } else if (TC_PTR_FROM_CHUNK(p) == context) {
00496 break;
00497 }
00498 }
00499 if (h == NULL) {
00500 return -1;
00501 }
00502
00503 return _talloc_free(h);
00504 }
00505
00506
00507
00508
00509
00510 int talloc_unlink(const void *context, void *ptr)
00511 {
00512 struct talloc_chunk *tc_p, *new_p;
00513 void *new_parent;
00514
00515 if (ptr == NULL) {
00516 return -1;
00517 }
00518
00519 if (context == NULL) {
00520 context = null_context;
00521 }
00522
00523 if (talloc_unreference(context, ptr) == 0) {
00524 return 0;
00525 }
00526
00527 if (context == NULL) {
00528 if (talloc_parent_chunk(ptr) != NULL) {
00529 return -1;
00530 }
00531 } else {
00532 if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) {
00533 return -1;
00534 }
00535 }
00536
00537 tc_p = talloc_chunk_from_ptr(ptr);
00538
00539 if (tc_p->refs == NULL) {
00540 return _talloc_free(ptr);
00541 }
00542
00543 new_p = talloc_parent_chunk(tc_p->refs);
00544 if (new_p) {
00545 new_parent = TC_PTR_FROM_CHUNK(new_p);
00546 } else {
00547 new_parent = NULL;
00548 }
00549
00550 if (talloc_unreference(new_parent, ptr) != 0) {
00551 return -1;
00552 }
00553
00554 talloc_steal(new_parent, ptr);
00555
00556 return 0;
00557 }
00558
00559
00560
00561
00562 static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
00563
00564 static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
00565 {
00566 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
00567 tc->name = talloc_vasprintf(ptr, fmt, ap);
00568 if (likely(tc->name)) {
00569 _talloc_set_name_const(tc->name, ".name");
00570 }
00571 return tc->name;
00572 }
00573
00574
00575
00576
00577 const char *talloc_set_name(const void *ptr, const char *fmt, ...)
00578 {
00579 const char *name;
00580 va_list ap;
00581 va_start(ap, fmt);
00582 name = talloc_set_name_v(ptr, fmt, ap);
00583 va_end(ap);
00584 return name;
00585 }
00586
00587
00588
00589
00590
00591
00592
00593 void *talloc_named(const void *context, size_t size, const char *fmt, ...)
00594 {
00595 va_list ap;
00596 void *ptr;
00597 const char *name;
00598
00599 ptr = __talloc(context, size);
00600 if (unlikely(ptr == NULL)) return NULL;
00601
00602 va_start(ap, fmt);
00603 name = talloc_set_name_v(ptr, fmt, ap);
00604 va_end(ap);
00605
00606 if (unlikely(name == NULL)) {
00607 _talloc_free(ptr);
00608 return NULL;
00609 }
00610
00611 return ptr;
00612 }
00613
00614
00615
00616
00617 const char *talloc_get_name(const void *ptr)
00618 {
00619 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
00620 if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) {
00621 return ".reference";
00622 }
00623 if (likely(tc->name)) {
00624 return tc->name;
00625 }
00626 return "UNNAMED";
00627 }
00628
00629
00630
00631
00632
00633
00634 void *talloc_check_name(const void *ptr, const char *name)
00635 {
00636 const char *pname;
00637 if (unlikely(ptr == NULL)) return NULL;
00638 pname = talloc_get_name(ptr);
00639 if (likely(pname == name || strcmp(pname, name) == 0)) {
00640 return discard_const_p(void, ptr);
00641 }
00642 return NULL;
00643 }
00644
00645
00646
00647
00648
00649 void *talloc_init(const char *fmt, ...)
00650 {
00651 va_list ap;
00652 void *ptr;
00653 const char *name;
00654
00655
00656
00657
00658
00659
00660 talloc_enable_null_tracking();
00661
00662 ptr = __talloc(NULL, 0);
00663 if (unlikely(ptr == NULL)) return NULL;
00664
00665 va_start(ap, fmt);
00666 name = talloc_set_name_v(ptr, fmt, ap);
00667 va_end(ap);
00668
00669 if (unlikely(name == NULL)) {
00670 _talloc_free(ptr);
00671 return NULL;
00672 }
00673
00674 return ptr;
00675 }
00676
00677
00678
00679
00680
00681
00682 void talloc_free_children(void *ptr)
00683 {
00684 struct talloc_chunk *tc;
00685
00686 if (unlikely(ptr == NULL)) {
00687 return;
00688 }
00689
00690 tc = talloc_chunk_from_ptr(ptr);
00691
00692 while (tc->child) {
00693
00694
00695
00696
00697
00698 void *child = TC_PTR_FROM_CHUNK(tc->child);
00699 const void *new_parent = null_context;
00700 if (unlikely(tc->child->refs)) {
00701 struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
00702 if (p) new_parent = TC_PTR_FROM_CHUNK(p);
00703 }
00704 if (unlikely(_talloc_free(child) == -1)) {
00705 if (new_parent == null_context) {
00706 struct talloc_chunk *p = talloc_parent_chunk(ptr);
00707 if (p) new_parent = TC_PTR_FROM_CHUNK(p);
00708 }
00709 talloc_steal(new_parent, child);
00710 }
00711 }
00712 }
00713
00714
00715
00716
00717 void *_talloc(const void *context, size_t size)
00718 {
00719 return __talloc(context, size);
00720 }
00721
00722
00723
00724
00725 void talloc_set_name_const(const void *ptr, const char *name)
00726 {
00727 _talloc_set_name_const(ptr, name);
00728 }
00729
00730
00731
00732
00733
00734
00735 void *talloc_named_const(const void *context, size_t size, const char *name)
00736 {
00737 return _talloc_named_const(context, size, name);
00738 }
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748 int talloc_free(void *ptr)
00749 {
00750 return _talloc_free(ptr);
00751 }
00752
00753
00754
00755
00756
00757
00758
00759 void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name)
00760 {
00761 struct talloc_chunk *tc;
00762 void *new_ptr;
00763
00764
00765 if (unlikely(size == 0)) {
00766 _talloc_free(ptr);
00767 return NULL;
00768 }
00769
00770 if (unlikely(size >= MAX_TALLOC_SIZE)) {
00771 return NULL;
00772 }
00773
00774
00775 if (ptr == NULL) {
00776 return _talloc_named_const(context, size, name);
00777 }
00778
00779 tc = talloc_chunk_from_ptr(ptr);
00780
00781
00782 if (unlikely(tc->refs)) {
00783 return NULL;
00784 }
00785
00786
00787 tc->flags |= TALLOC_FLAG_FREE;
00788
00789 #if ALWAYS_REALLOC
00790 new_ptr = malloc(size + TC_HDR_SIZE);
00791 if (new_ptr) {
00792 memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE);
00793 free(tc);
00794 }
00795 #else
00796 new_ptr = realloc(tc, size + TC_HDR_SIZE);
00797 #endif
00798 if (unlikely(!new_ptr)) {
00799 tc->flags &= ~TALLOC_FLAG_FREE;
00800 return NULL;
00801 }
00802
00803 tc = (struct talloc_chunk *)new_ptr;
00804 tc->flags &= ~TALLOC_FLAG_FREE;
00805 if (tc->parent) {
00806 tc->parent->child = tc;
00807 }
00808 if (tc->child) {
00809 tc->child->parent = tc;
00810 }
00811
00812 if (tc->prev) {
00813 tc->prev->next = tc;
00814 }
00815 if (tc->next) {
00816 tc->next->prev = tc;
00817 }
00818
00819 tc->size = size;
00820 _talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
00821
00822 return TC_PTR_FROM_CHUNK(tc);
00823 }
00824
00825
00826
00827
00828
00829 void *_talloc_move(const void *new_ctx, const void *_pptr)
00830 {
00831 const void **pptr = discard_const_p(const void *,_pptr);
00832 void *ret = _talloc_steal(new_ctx, *pptr);
00833 (*pptr) = NULL;
00834 return ret;
00835 }
00836
00837
00838
00839
00840 size_t talloc_total_size(const void *ptr)
00841 {
00842 size_t total = 0;
00843 struct talloc_chunk *c, *tc;
00844
00845 if (ptr == NULL) {
00846 ptr = null_context;
00847 }
00848 if (ptr == NULL) {
00849 return 0;
00850 }
00851
00852 tc = talloc_chunk_from_ptr(ptr);
00853
00854 if (tc->flags & TALLOC_FLAG_LOOP) {
00855 return 0;
00856 }
00857
00858 tc->flags |= TALLOC_FLAG_LOOP;
00859
00860 total = tc->size;
00861 for (c=tc->child;c;c=c->next) {
00862 total += talloc_total_size(TC_PTR_FROM_CHUNK(c));
00863 }
00864
00865 tc->flags &= ~TALLOC_FLAG_LOOP;
00866
00867 return total;
00868 }
00869
00870
00871
00872
00873 size_t talloc_total_blocks(const void *ptr)
00874 {
00875 size_t total = 0;
00876 struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
00877
00878 if (tc->flags & TALLOC_FLAG_LOOP) {
00879 return 0;
00880 }
00881
00882 tc->flags |= TALLOC_FLAG_LOOP;
00883
00884 total++;
00885 for (c=tc->child;c;c=c->next) {
00886 total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c));
00887 }
00888
00889 tc->flags &= ~TALLOC_FLAG_LOOP;
00890
00891 return total;
00892 }
00893
00894
00895
00896
00897 size_t talloc_reference_count(const void *ptr)
00898 {
00899 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
00900 struct talloc_reference_handle *h;
00901 size_t ret = 0;
00902
00903 for (h=tc->refs;h;h=h->next) {
00904 ret++;
00905 }
00906 return ret;
00907 }
00908
00909
00910
00911
00912 void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
00913 void (*callback)(const void *ptr,
00914 int depth, int max_depth,
00915 int is_ref,
00916 void *private_data),
00917 void *private_data)
00918 {
00919 struct talloc_chunk *c, *tc;
00920
00921 if (ptr == NULL) {
00922 ptr = null_context;
00923 }
00924 if (ptr == NULL) return;
00925
00926 tc = talloc_chunk_from_ptr(ptr);
00927
00928 if (tc->flags & TALLOC_FLAG_LOOP) {
00929 return;
00930 }
00931
00932 callback(ptr, depth, max_depth, 0, private_data);
00933
00934 if (max_depth >= 0 && depth >= max_depth) {
00935 return;
00936 }
00937
00938 tc->flags |= TALLOC_FLAG_LOOP;
00939 for (c=tc->child;c;c=c->next) {
00940 if (c->name == TALLOC_MAGIC_REFERENCE) {
00941 struct talloc_reference_handle *h = (struct talloc_reference_handle *)TC_PTR_FROM_CHUNK(c);
00942 callback(h->ptr, depth + 1, max_depth, 1, private_data);
00943 } else {
00944 talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1, max_depth, callback, private_data);
00945 }
00946 }
00947 tc->flags &= ~TALLOC_FLAG_LOOP;
00948 }
00949
00950 static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_f)
00951 {
00952 const char *name = talloc_get_name(ptr);
00953 FILE *f = (FILE *)_f;
00954
00955 if (is_ref) {
00956 fprintf(f, "%*sreference to: %s\n", depth*4, "", name);
00957 return;
00958 }
00959
00960 if (depth == 0) {
00961 fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n",
00962 (max_depth < 0 ? "full " :""), name,
00963 (unsigned long)talloc_total_size(ptr),
00964 (unsigned long)talloc_total_blocks(ptr));
00965 return;
00966 }
00967
00968 fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n",
00969 depth*4, "",
00970 name,
00971 (unsigned long)talloc_total_size(ptr),
00972 (unsigned long)talloc_total_blocks(ptr),
00973 (int)talloc_reference_count(ptr), ptr);
00974
00975 #if 0
00976 fprintf(f, "content: ");
00977 if (talloc_total_size(ptr)) {
00978 int tot = talloc_total_size(ptr);
00979 int i;
00980
00981 for (i = 0; i < tot; i++) {
00982 if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126)) {
00983 fprintf(f, "%c", ((char *)ptr)[i]);
00984 } else {
00985 fprintf(f, "~%02x", ((char *)ptr)[i]);
00986 }
00987 }
00988 }
00989 fprintf(f, "\n");
00990 #endif
00991 }
00992
00993
00994
00995
00996 void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f)
00997 {
00998 talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_depth_FILE_helper, f);
00999 fflush(f);
01000 }
01001
01002
01003
01004
01005 void talloc_report_full(const void *ptr, FILE *f)
01006 {
01007 talloc_report_depth_file(ptr, 0, -1, f);
01008 }
01009
01010
01011
01012
01013 void talloc_report(const void *ptr, FILE *f)
01014 {
01015 talloc_report_depth_file(ptr, 0, 1, f);
01016 }
01017
01018
01019
01020
01021 static void talloc_report_null(void)
01022 {
01023 if (talloc_total_size(null_context) != 0) {
01024 talloc_report(null_context, stderr);
01025 }
01026 }
01027
01028
01029
01030
01031 static void talloc_report_null_full(void)
01032 {
01033 if (talloc_total_size(null_context) != 0) {
01034 talloc_report_full(null_context, stderr);
01035 }
01036 }
01037
01038
01039
01040
01041 void talloc_enable_null_tracking(void)
01042 {
01043 if (null_context == NULL) {
01044 null_context = _talloc_named_const(NULL, 0, "null_context");
01045 }
01046 }
01047
01048
01049
01050
01051 void talloc_disable_null_tracking(void)
01052 {
01053 _talloc_free(null_context);
01054 null_context = NULL;
01055 }
01056
01057
01058
01059
01060 void talloc_enable_leak_report(void)
01061 {
01062 talloc_enable_null_tracking();
01063 atexit(talloc_report_null);
01064 }
01065
01066
01067
01068
01069 void talloc_enable_leak_report_full(void)
01070 {
01071 talloc_enable_null_tracking();
01072 atexit(talloc_report_null_full);
01073 }
01074
01075
01076
01077
01078 void *_talloc_zero(const void *ctx, size_t size, const char *name)
01079 {
01080 void *p = _talloc_named_const(ctx, size, name);
01081
01082 if (p) {
01083 memset(p, '\0', size);
01084 }
01085
01086 return p;
01087 }
01088
01089
01090
01091
01092 void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name)
01093 {
01094 void *newp = _talloc_named_const(t, size, name);
01095
01096 if (likely(newp)) {
01097 memcpy(newp, p, size);
01098 }
01099
01100 return newp;
01101 }
01102
01103
01104
01105
01106 char *talloc_strdup(const void *t, const char *p)
01107 {
01108 char *ret;
01109 if (!p) {
01110 return NULL;
01111 }
01112 ret = (char *)talloc_memdup(t, p, strlen(p) + 1);
01113 if (likely(ret)) {
01114 _talloc_set_name_const(ret, ret);
01115 }
01116 return ret;
01117 }
01118
01119
01120
01121
01122 char *talloc_append_string(const void *t, char *orig, const char *append)
01123 {
01124 char *ret;
01125 size_t olen = strlen(orig);
01126 size_t alenz;
01127
01128 if (!append)
01129 return orig;
01130
01131 alenz = strlen(append) + 1;
01132
01133 ret = talloc_realloc(t, orig, char, olen + alenz);
01134 if (!ret)
01135 return NULL;
01136
01137
01138 memcpy(&ret[olen], append, alenz);
01139
01140 return ret;
01141 }
01142
01143
01144
01145
01146 char *talloc_strndup(const void *t, const char *p, size_t n)
01147 {
01148 size_t len;
01149 char *ret;
01150
01151 for (len=0; len<n && p[len]; len++) ;
01152
01153 ret = (char *)__talloc(t, len + 1);
01154 if (!ret) { return NULL; }
01155 memcpy(ret, p, len);
01156 ret[len] = 0;
01157 _talloc_set_name_const(ret, ret);
01158 return ret;
01159 }
01160
01161 #ifndef HAVE_VA_COPY
01162 #ifdef HAVE___VA_COPY
01163 #define va_copy(dest, src) __va_copy(dest, src)
01164 #else
01165 #define va_copy(dest, src) (dest) = (src)
01166 #endif
01167 #endif
01168
01169 char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
01170 {
01171 int len;
01172 char *ret;
01173 va_list ap2;
01174 char c;
01175
01176
01177 va_copy(ap2, ap);
01178 len = vsnprintf(&c, 1, fmt, ap2);
01179 va_end(ap2);
01180 if (len < 0) {
01181 return NULL;
01182 }
01183
01184 ret = (char *)__talloc(t, len+1);
01185 if (ret) {
01186 va_copy(ap2, ap);
01187 vsnprintf(ret, len+1, fmt, ap2);
01188 va_end(ap2);
01189 _talloc_set_name_const(ret, ret);
01190 }
01191
01192 return ret;
01193 }
01194
01195
01196
01197
01198
01199
01200 char *talloc_asprintf(const void *t, const char *fmt, ...)
01201 {
01202 va_list ap;
01203 char *ret;
01204
01205 va_start(ap, fmt);
01206 ret = talloc_vasprintf(t, fmt, ap);
01207 va_end(ap);
01208 return ret;
01209 }
01210
01211
01212
01213
01214
01215
01216
01217 char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
01218 {
01219 struct talloc_chunk *tc;
01220 int len, s_len;
01221 va_list ap2;
01222 char c;
01223
01224 if (s == NULL) {
01225 return talloc_vasprintf(NULL, fmt, ap);
01226 }
01227
01228 tc = talloc_chunk_from_ptr(s);
01229
01230 s_len = tc->size - 1;
01231
01232 va_copy(ap2, ap);
01233 len = vsnprintf(&c, 1, fmt, ap2);
01234 va_end(ap2);
01235
01236 if (len <= 0) {
01237
01238
01239
01240
01241
01242
01243 return s;
01244 }
01245
01246 s = talloc_realloc(NULL, s, char, s_len + len+1);
01247 if (!s) return NULL;
01248
01249 va_copy(ap2, ap);
01250 vsnprintf(s+s_len, len+1, fmt, ap2);
01251 va_end(ap2);
01252 _talloc_set_name_const(s, s);
01253
01254 return s;
01255 }
01256
01257
01258
01259
01260
01261
01262 char *talloc_asprintf_append(char *s, const char *fmt, ...)
01263 {
01264 va_list ap;
01265
01266 va_start(ap, fmt);
01267 s = talloc_vasprintf_append(s, fmt, ap);
01268 va_end(ap);
01269 return s;
01270 }
01271
01272
01273
01274
01275 void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
01276 {
01277 if (count >= MAX_TALLOC_SIZE/el_size) {
01278 return NULL;
01279 }
01280 return _talloc_named_const(ctx, el_size * count, name);
01281 }
01282
01283
01284
01285
01286 void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name)
01287 {
01288 if (count >= MAX_TALLOC_SIZE/el_size) {
01289 return NULL;
01290 }
01291 return _talloc_zero(ctx, el_size * count, name);
01292 }
01293
01294
01295
01296
01297 void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
01298 {
01299 if (count >= MAX_TALLOC_SIZE/el_size) {
01300 return NULL;
01301 }
01302 return _talloc_realloc(ctx, ptr, el_size * count, name);
01303 }
01304
01305
01306
01307
01308
01309
01310 void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
01311 {
01312 return _talloc_realloc(context, ptr, size, NULL);
01313 }
01314
01315
01316 static int talloc_autofree_destructor(void *ptr)
01317 {
01318 autofree_context = NULL;
01319 return 0;
01320 }
01321
01322 static void talloc_autofree(void)
01323 {
01324 _talloc_free(autofree_context);
01325 }
01326
01327
01328
01329
01330
01331 void *talloc_autofree_context(void)
01332 {
01333 if (autofree_context == NULL) {
01334 autofree_context = _talloc_named_const(NULL, 0, "autofree_context");
01335 talloc_set_destructor(autofree_context, talloc_autofree_destructor);
01336 atexit(talloc_autofree);
01337 }
01338 return autofree_context;
01339 }
01340
01341 size_t talloc_get_size(const void *context)
01342 {
01343 struct talloc_chunk *tc;
01344
01345 if (context == NULL)
01346 return 0;
01347
01348 tc = talloc_chunk_from_ptr(context);
01349
01350 return tc->size;
01351 }
01352
01353
01354
01355
01356 void *talloc_find_parent_byname(const void *context, const char *name)
01357 {
01358 struct talloc_chunk *tc;
01359
01360 if (context == NULL) {
01361 return NULL;
01362 }
01363
01364 tc = talloc_chunk_from_ptr(context);
01365 while (tc) {
01366 if (tc->name && strcmp(tc->name, name) == 0) {
01367 return TC_PTR_FROM_CHUNK(tc);
01368 }
01369 while (tc && tc->prev) tc = tc->prev;
01370 if (tc) {
01371 tc = tc->parent;
01372 }
01373 }
01374 return NULL;
01375 }
01376
01377
01378
01379
01380 void talloc_show_parents(const void *context, FILE *file)
01381 {
01382 struct talloc_chunk *tc;
01383
01384 if (context == NULL) {
01385 fprintf(file, "talloc no parents for NULL\n");
01386 return;
01387 }
01388
01389 tc = talloc_chunk_from_ptr(context);
01390 fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
01391 while (tc) {
01392 fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)));
01393 while (tc && tc->prev) tc = tc->prev;
01394 if (tc) {
01395 tc = tc->parent;
01396 }
01397 }
01398 fflush(file);
01399 }
01400
01401
01402
01403
01404 int talloc_is_parent(const void *context, const void *ptr)
01405 {
01406 struct talloc_chunk *tc;
01407
01408 if (context == NULL) {
01409 return 0;
01410 }
01411
01412 tc = talloc_chunk_from_ptr(context);
01413 while (tc) {
01414 if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1;
01415 while (tc && tc->prev) tc = tc->prev;
01416 if (tc) {
01417 tc = tc->parent;
01418 }
01419 }
01420 return 0;
01421 }