r2677: - fixed a bug in the recursive logic talloc_free() when there are
authorAndrew Tridgell <tridge@samba.org>
Mon, 27 Sep 2004 08:38:13 +0000 (08:38 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:59:21 +0000 (12:59 -0500)
  circular references (circular references are allowed, they just need
  to be handled carefully inside talloc)

- mark talloc_reference() pointers nicely in the --leak-report-full
  code, so you see what has a reference to what in a useful manner

source/lib/talloc.c

index 55b97717c7edd30cbe802fd32d3a76eec6f0f0f2..5d22754f5b51cfc505b82ed2ee2952cb61fb1fc4 100644 (file)
@@ -146,7 +146,7 @@ static int talloc_reference_destructor(void *ptr)
 void *talloc_reference(const void *context, const void *ptr)
 {
        void **handle;
-       handle = _talloc(context, sizeof(void *));
+       handle = talloc_named_const(context, sizeof(void *), ".reference");
        if (handle == NULL) {
                return NULL;
        }
@@ -169,6 +169,9 @@ static void talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
 {
        struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
        tc->name = talloc_vasprintf(ptr, fmt, ap);
+       if (tc->name) {
+               talloc_set_name_const(tc->name, ".name");
+       }
 }
 
 /*
@@ -267,7 +270,6 @@ void *talloc_init(const char *fmt, ...) _PRINTF_ATTRIBUTE(1,2)
 }
 
 
-
 /* 
    free a talloc pointer. This also frees all child pointers of this 
    pointer recursively
@@ -278,7 +280,7 @@ void *talloc_init(const char *fmt, ...) _PRINTF_ATTRIBUTE(1,2)
 */
 int talloc_free(void *ptr)
 {
-       struct talloc_chunk *tc;
+       struct talloc_chunk *tc, *tc2, *next;
 
        if (ptr == NULL) {
                return -1;
@@ -286,23 +288,26 @@ int talloc_free(void *ptr)
 
        tc = talloc_chunk_from_ptr(ptr);
 
-       tc->ref_count--;
-       if (tc->ref_count != 0) {
-               return -1;
-       }
-
-       if (tc->destructor && tc->destructor(ptr) == -1) {
-               tc->ref_count++;
+       if (tc->ref_count > 1) {
+               tc->ref_count--;
                return -1;
        }
 
-       while (tc->child) {
-               if (talloc_free(tc->child + 1) != 0) {
-                       tc->child->parent = NULL;
-                       break;
+       /* while processing the free, increase the reference count
+          so we don't recurse into this function */
+       tc->ref_count++;
+       if (tc->destructor) {
+               if (tc->destructor(ptr) == -1) {
+                       tc->ref_count--;
+                       return -1;
                }
        }
 
+       for (tc2=tc->child;tc2;tc2=next) {
+               next = tc2->next;
+               talloc_free(tc2 + 1);
+       }
+       
        if (tc->parent) {
                DLIST_REMOVE(tc->parent->child, tc);
                if (tc->parent->child) {
@@ -313,6 +318,10 @@ int talloc_free(void *ptr)
                if (tc->next) tc->next->prev = tc->prev;
        }
 
+       if (tc->child) {
+               tc->child->parent = tc->parent;
+       }
+
        tc->magic = TALLOC_MAGIC_FREE;
 
        free(tc);
@@ -445,12 +454,20 @@ static void talloc_report_depth(const void *ptr, FILE *f, int depth)
        struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
 
        for (c=tc->child;c;c=c->next) {
-               fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks\n", 
-                       depth*2, "",
-                       talloc_get_name(c+1),
-                       (unsigned long)talloc_total_size(c+1),
-                       (unsigned long)talloc_total_blocks(c+1));
-               talloc_report_depth(c+1, f, depth+1);
+               const char *name = talloc_get_name(c+1);
+               if (strcmp(name, ".reference") == 0) {
+                       void **handle = (void *)(c+1);
+                       const char *name2 = talloc_get_name(*handle);
+                       fprintf(f, "%*sreference to: %s\n", depth*4, "", name2);
+               } else {
+                       fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n", 
+                               depth*4, "",
+                               name,
+                               (unsigned long)talloc_total_size(c+1),
+                               (unsigned long)talloc_total_blocks(c+1),
+                               c->ref_count);
+                       talloc_report_depth(c+1, f, depth+1);
+               }
        }
 
 }
@@ -460,6 +477,11 @@ static void talloc_report_depth(const void *ptr, FILE *f, int depth)
 */
 void talloc_report_full(const void *ptr, FILE *f)
 {
+       if (ptr == NULL) {
+               ptr = null_context;
+       }
+       if (ptr == NULL) return;
+
        fprintf(f,"full talloc report on '%s' (total %lu bytes in %lu blocks)\n", 
                talloc_get_name(ptr), 
                (unsigned long)talloc_total_size(ptr),
@@ -473,13 +495,20 @@ void talloc_report_full(const void *ptr, FILE *f)
 */
 void talloc_report(const void *ptr, FILE *f)
 {
-       struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
+       struct talloc_chunk *c, *tc;
 
+       if (ptr == NULL) {
+               ptr = null_context;
+       }
+       if (ptr == NULL) return;
+       
        fprintf(f,"talloc report on '%s' (total %lu bytes in %lu blocks)\n", 
                talloc_get_name(ptr), 
                (unsigned long)talloc_total_size(ptr),
                (unsigned long)talloc_total_blocks(ptr));
 
+       tc = talloc_chunk_from_ptr(ptr);
+
        for (c=tc->child;c;c=c->next) {
                fprintf(f, "\t%-30s contains %6lu bytes in %3lu blocks\n", 
                        talloc_get_name(c+1),