summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/lib/talloc.c45
-rw-r--r--source4/torture/local/talloc.c138
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;
}