lib/talloc/talloc.c

説明を見る。
00001 /* 
00002    Samba Unix SMB/CIFS implementation.
00003 
00004    Samba trivial allocation library - new interface
00005 
00006    NOTE: Please read talloc_guide.txt for full documentation
00007 
00008    Copyright (C) Andrew Tridgell 2004
00009    Copyright (C) Stefan Metzmacher 2006
00010    
00011      ** NOTE! The following LGPL license applies to the talloc
00012      ** library. This does NOT imply that all of Samba is released
00013      ** under the LGPL
00014    
00015    This library is free software; you can redistribute it and/or
00016    modify it under the terms of the GNU Lesser General Public
00017    License as published by the Free Software Foundation; either
00018    version 2 of the License, or (at your option) any later version.
00019 
00020    This library is distributed in the hope that it will be useful,
00021    but WITHOUT ANY WARRANTY; without even the implied warranty of
00022    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00023    Lesser General Public License for more details.
00024 
00025    You should have received a copy of the GNU Lesser General Public
00026    License along with this library; if not, write to the Free Software
00027    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00028 */
00029 
00030 /*
00031   inspired by http://swapped.cc/halloc/
00032 */
00033 
00034 #ifdef _SAMBA_BUILD_
00035 #include "version.h"
00036 #if (SAMBA_VERSION_MAJOR<4)
00037 #include "includes.h"
00038 /* This is to circumvent SAMBA3's paranoid malloc checker. Here in this file
00039  * we trust ourselves... */
00040 #ifdef malloc
00041 #undef malloc
00042 #endif
00043 #ifdef realloc
00044 #undef realloc
00045 #endif
00046 #define _TALLOC_SAMBA3
00047 #endif /* (SAMBA_VERSION_MAJOR<4) */
00048 #endif /* _SAMBA_BUILD_ */
00049 
00050 #ifndef _TALLOC_SAMBA3
00051 #include "replace.h"
00052 #include "talloc.h"
00053 #endif /* not _TALLOC_SAMBA3 */
00054 
00055 /* use this to force every realloc to change the pointer, to stress test
00056    code that might not cope */
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 /* by default we abort when given a bad pointer (such as when talloc_free() is called 
00067    on a pointer that came from malloc() */
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 /* these macros gain us a few percent of speed on gcc */
00081 #if (__GNUC__ >= 3)
00082 /* the strange !! is to ensure that __builtin_expect() takes either 0 or 1
00083    as its first argument */
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 /* this null_context is only used if talloc_enable_leak_report() or
00092    talloc_enable_leak_report_full() is called, otherwise it remains
00093    NULL
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 /* 16 byte alignment seems to keep everyone happy */
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 /* panic if we get a bad magic value */
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 /* hook into the front of the list */
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 /* remove an element from a list - element doesn't have to be in list. */
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   return the parent chunk of a pointer
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   find parents name
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    Allocate a bit of memory as a child of an existing pointer
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   setup a destructor to be called on free of a pointer
00241   the destructor should return 0 on success, or -1 on failure.
00242   if the destructor fails then the free is failed, and the memory can
00243   be continued to be used
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   increase the reference count on a piece of memory. 
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   helper for talloc_reference()
00264 
00265   this is referenced by a function pointer and should not be inline
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    more efficient way to add a name to a pointer - the name must point to a 
00276    true string constant
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   internal talloc_named_const()
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   make a secondary reference to a pointer, hanging off the given context.
00303   the pointer remains valid until both the original caller and this given
00304   context are freed.
00305   
00306   the major use for this is when two different structures need to reference the 
00307   same underlying data, and you want to be able to free the two instances separately,
00308   and in either order
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         /* note that we hang the destructor off the handle, not the
00323            main context as that allows the caller to still setup their
00324            own destructor on the context if they want to */
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    internal talloc_free call
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                 /* check this is a reference from a child or grantchild
00348                  * back to it's parent or grantparent
00349                  *
00350                  * in that case we need to remove the reference and
00351                  * call another instance of talloc_free() on the current
00352                  * pointer.
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                 /* we have a free loop - stop looping */
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                 /* we need to work out who will own an abandoned child
00394                    if it cannot be freed. In priority order, the first
00395                    choice is owner of any remaining reference to this
00396                    pointer, the second choice is our parent, and the
00397                    final choice is the null context. */
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    move a lump of memory from one talloc context to another return the
00420    ptr on success, or NULL if it could not be transferred.
00421    passing NULL as ptr will always return NULL with no side effects.
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   remove a secondary reference to a pointer. This undo's what
00479   talloc_reference() has done. The context and pointer arguments
00480   must match those given to a talloc_reference()
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   remove a specific parent context from a pointer. This is a more
00508   controlled varient of talloc_free()
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   add a name to an existing pointer - va_list version
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   add a name to an existing pointer
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   create a named talloc pointer. Any talloc pointer can be named, and
00590   talloc_named() operates just like talloc() except that it allows you
00591   to name the pointer.
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   return the name of a talloc ptr, or "UNNAMED"
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   check if a pointer has the given name. If it does, return the pointer,
00632   otherwise return NULL
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   this is for compatibility with older versions of talloc
00648 */
00649 void *talloc_init(const char *fmt, ...)
00650 {
00651         va_list ap;
00652         void *ptr;
00653         const char *name;
00654 
00655         /*
00656          * samba3 expects talloc_report_depth_cb(NULL, ...)
00657          * reports all talloc'ed memory, so we need to enable
00658          * null_tracking
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   this is a replacement for the Samba3 talloc_destroy_pool functionality. It
00679   should probably not be used in new code. It's in here to keep the talloc
00680   code consistent across Samba 3 and 4.
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                 /* we need to work out who will own an abandoned child
00694                    if it cannot be freed. In priority order, the first
00695                    choice is owner of any remaining reference to this
00696                    pointer, the second choice is our parent, and the
00697                    final choice is the null context. */
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    Allocate a bit of memory as a child of an existing pointer
00716 */
00717 void *_talloc(const void *context, size_t size)
00718 {
00719         return __talloc(context, size);
00720 }
00721 
00722 /*
00723   externally callable talloc_set_name_const()
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   create a named talloc pointer. Any talloc pointer can be named, and
00732   talloc_named() operates just like talloc() except that it allows you
00733   to name the pointer.
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    free a talloc pointer. This also frees all child pointers of this 
00742    pointer recursively
00743 
00744    return 0 if the memory is actually freed, otherwise -1. The memory
00745    will not be freed if the ref_count is > 1 or the destructor (if
00746    any) returns non-zero
00747 */
00748 int talloc_free(void *ptr)
00749 {
00750         return _talloc_free(ptr);
00751 }
00752 
00753 
00754 
00755 /*
00756   A talloc version of realloc. The context argument is only used if
00757   ptr is NULL
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         /* size zero is equivalent to free() */
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         /* realloc(NULL) is equivalent to malloc() */
00775         if (ptr == NULL) {
00776                 return _talloc_named_const(context, size, name);
00777         }
00778 
00779         tc = talloc_chunk_from_ptr(ptr);
00780 
00781         /* don't allow realloc on referenced pointers */
00782         if (unlikely(tc->refs)) {
00783                 return NULL;
00784         }
00785 
00786         /* by resetting magic we catch users of the old memory */
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   a wrapper around talloc_steal() for situations where you are moving a pointer
00827   between two structures, and want the old pointer to be set to NULL
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   return the total size of a talloc pool (subtree)
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   return the total number of blocks in a talloc pool (subtree)
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   return the number of external references to a pointer
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   report on memory usage by all children of a pointer, giving a full tree view
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   report on memory usage by all children of a pointer, giving a full tree view
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   report on memory usage by all children of a pointer, giving a full tree view
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   report on memory usage by all children of a pointer
01012 */
01013 void talloc_report(const void *ptr, FILE *f)
01014 {
01015         talloc_report_depth_file(ptr, 0, 1, f);
01016 }
01017 
01018 /*
01019   report on any memory hanging off the null context
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   report on any memory hanging off the null context
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   enable tracking of the NULL context
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   disable tracking of the NULL context
01050 */
01051 void talloc_disable_null_tracking(void)
01052 {
01053         _talloc_free(null_context);
01054         null_context = NULL;
01055 }
01056 
01057 /*
01058   enable leak reporting on exit
01059 */
01060 void talloc_enable_leak_report(void)
01061 {
01062         talloc_enable_null_tracking();
01063         atexit(talloc_report_null);
01064 }
01065 
01066 /*
01067   enable full leak reporting on exit
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    talloc and zero memory. 
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   memdup with a talloc. 
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   strdup with a talloc 
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  append to a talloced string 
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         /* append the string with the trailing \0 */
01138         memcpy(&ret[olen], append, alenz);
01139 
01140         return ret;
01141 }
01142 
01143 /*
01144   strndup with a talloc 
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         /* this call looks strange, but it makes it work on older solaris boxes */
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   Perform string formatting, and return a pointer to newly allocated
01198   memory holding the result, inside a memory pool.
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  * Realloc @p s to append the formatted result of @p fmt and @p ap,
01214  * and return @p s, which may have moved.  Good for gradually
01215  * accumulating output into a string buffer.
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                 /* Either the vsnprintf failed or the format resulted in
01238                  * no characters being formatted. In the former case, we
01239                  * ought to return NULL, in the latter we ought to return
01240                  * the original string. Most current callers of this 
01241                  * function expect it to never return NULL.
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   Realloc @p s to append the formatted result of @p fmt and return @p
01259   s, which may have moved.  Good for gradually accumulating output
01260   into a string buffer.
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   alloc an array, checking for integer overflow in the array size
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   alloc an zero array, checking for integer overflow in the array size
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   realloc an array, checking for integer overflow in the array size
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   a function version of talloc_realloc(), so it can be passed as a function pointer
01307   to libraries that want a realloc function (a realloc function encapsulates
01308   all the basic capabilities of an allocation library, which is why this is useful)
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   return a context which will be auto-freed on exit
01329   this is useful for reducing the noise in leak reports
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   find a parent of this context that has the given name, if any
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   show the parentage of a context
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   return 1 if ptr is a parent of context
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 }

Sambaに対してSat Aug 29 21:22:59 2009に生成されました。  doxygen 1.4.7