diff options
Diffstat (limited to 'source4')
-rw-r--r-- | source4/lib/talloc.c | 45 | ||||
-rw-r--r-- | source4/torture/local/talloc.c | 138 |
2 files changed, 164 insertions, 19 deletions
diff --git a/source4/lib/talloc.c b/source4/lib/talloc.c index d0056d7b2a..bb2ed9449c 100644 --- a/source4/lib/talloc.c +++ b/source4/lib/talloc.c @@ -170,6 +170,34 @@ void *talloc_reference(const void *context, const void *ptr) return handle->ptr; } +/* + remove a secondary reference to a pointer. This undo's what + talloc_reference() has done. The context and pointer arguments + must match those given to a talloc_reference() +*/ +void *talloc_unreference(const void *context, const void *ptr) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + struct talloc_reference_handle *h; + + if (context == NULL) { + context = null_context; + } + + for (h=tc->refs;h;h=h->next) { + struct talloc_chunk *tc2 = talloc_chunk_from_ptr(h); + const void *parent = tc2->parent?tc2->parent+1:null_context; + if (parent == context) break; + } + if (h == NULL) { + return NULL; + } + + talloc_set_destructor(h, NULL); + DLIST_REMOVE(tc->refs, h); + talloc_free(h); + return discard_const(ptr); +} /* add a name to an existing pointer - va_list version @@ -318,8 +346,21 @@ int talloc_free(void *ptr) } while (tc->child) { - talloc_free(talloc_steal(tc->parent?tc->parent+1:null_context, - tc->child+1)); + /* we need to work out who will own an abandoned child + if it cannot be freed. In priority order, the first + choice is owner of any remaining reference to this + pointer, the second choice is our parent, and the + final choice is the null context. */ + void *child = tc->child+1; + const void *new_parent = null_context; + if (tc->child->refs) { + struct talloc_chunk *ref = talloc_chunk_from_ptr(tc->child->refs); + if (ref->parent) new_parent = ref->parent+1; + } + if (new_parent == null_context && tc->parent) { + new_parent = tc->parent+1; + } + talloc_free(talloc_steal(new_parent, child)); } if (tc->parent) { diff --git a/source4/torture/local/talloc.c b/source4/torture/local/talloc.c index 4c353ecbbd..9f518eabf2 100644 --- a/source4/torture/local/talloc.c +++ b/source4/torture/local/talloc.c @@ -22,20 +22,6 @@ #include "includes.h" -static struct timeval tp1,tp2; - -static void start_timer(void) -{ - gettimeofday(&tp1,NULL); -} - -static double end_timer(void) -{ - gettimeofday(&tp2,NULL); - return((tp2.tv_sec - tp1.tv_sec) + - (tp2.tv_usec - tp1.tv_usec)*1.0e-6); -} - /* test references */ @@ -68,7 +54,7 @@ static BOOL test_ref1(void) talloc_report_full(NULL, stdout); if (talloc_total_size(NULL) != 0) { - printf("non-zero total size\n"); + printf("failed: non-zero total size\n"); return False; } @@ -93,21 +79,134 @@ static BOOL test_ref2(void) r1 = talloc_named_const(NULL, 1, "r1"); ref = talloc_reference(r1, p2); talloc_report_full(NULL, stdout); + printf("Freeing ref\n"); talloc_free(ref); talloc_report_full(NULL, stdout); + printf("Freeing p2\n"); talloc_free(p2); talloc_report_full(NULL, stdout); + printf("Freeing p1\n"); talloc_free(p1); talloc_report_full(NULL, stdout); + printf("Freeing r1\n"); talloc_free(r1); talloc_report_full(NULL, stdout); if (talloc_total_size(NULL) != 0) { - printf("non-zero total size\n"); + printf("failed: non-zero total size\n"); + return False; + } + + return True; +} + +/* + test references +*/ +static BOOL test_ref3(void) +{ + void *p1, *p2, *ref, *r1; + + printf("TESTING PARENT REFERENCE FREE\n"); + + p1 = talloc_named_const(NULL, 1, "p1"); + p2 = talloc_named_const(NULL, 1, "p2"); + + r1 = talloc_named_const(p1, 1, "r1"); + + ref = talloc_reference(p2, r1); + + talloc_report_full(NULL, stdout); + + printf("Freeing p1\n"); + talloc_free(p1); + talloc_report_full(NULL, stdout); + + printf("Freeing p2\n"); + talloc_free(p2); + talloc_report_full(NULL, stdout); + + if (talloc_total_size(NULL) != 0) { + printf("failed: non-zero total size\n"); + return False; + } + + return True; +} + +/* + test references +*/ +static BOOL test_ref4(void) +{ + void *p1, *p2, *ref, *r1; + + printf("TESTING REFERRER REFERENCE FREE\n"); + + p1 = talloc_named_const(NULL, 1, "p1"); + talloc_named_const(p1, 1, "x1"); + talloc_named_const(p1, 1, "x2"); + talloc_named_const(p1, 1, "x3"); + p2 = talloc_named_const(p1, 1, "p2"); + + r1 = talloc_named_const(NULL, 1, "r1"); + ref = talloc_reference(r1, p2); + talloc_report_full(NULL, stdout); + + printf("Freeing r1\n"); + talloc_free(r1); + talloc_report_full(NULL, stdout); + + printf("Freeing p2\n"); + talloc_free(p2); + talloc_report_full(NULL, stdout); + + printf("Freeing p1\n"); + talloc_free(p1); + talloc_report_full(NULL, stdout); + + if (talloc_total_size(NULL) != 0) { + printf("failed: non-zero total size\n"); + return False; + } + + return True; +} + + +/* + test references +*/ +static BOOL test_unref1(void) +{ + void *p1, *p2, *ref, *r1; + + printf("TESTING UNREFERENCE\n"); + + p1 = talloc_named_const(NULL, 1, "p1"); + talloc_named_const(p1, 1, "x1"); + talloc_named_const(p1, 1, "x2"); + talloc_named_const(p1, 1, "x3"); + p2 = talloc_named_const(p1, 1, "p2"); + + r1 = talloc_named_const(p1, 1, "r1"); + ref = talloc_reference(r1, p2); + talloc_report_full(NULL, stdout); + + printf("Unreferencing r1\n"); + talloc_unreference(r1, p2); + talloc_report_full(NULL, stdout); + + printf("Freeing p1\n"); + talloc_free(p1); + talloc_report_full(NULL, stdout); + + if (talloc_total_size(NULL) != 0) { + printf("failed: non-zero total size\n"); return False; } @@ -137,6 +236,8 @@ static BOOL test_speed(void) printf("talloc: %.0f ops/sec\n", count/end_timer()); + talloc_free(ctx); + start_timer(); count = 0; do { @@ -164,7 +265,10 @@ BOOL torture_local_talloc(int dummy) ret &= test_ref1(); ret &= test_ref2(); + ret &= test_ref3(); + ret &= test_ref4(); + ret &= test_unref1(); ret &= test_speed(); - return True; + return ret; } |