talloc: Make explicit free behave the same as implicit free
authorSam Liddicott <sam@liddicott.com>
Fri, 10 Jul 2009 10:45:02 +0000 (11:45 +0100)
committerStefan Metzmacher <metze@samba.org>
Tue, 14 Jul 2009 09:24:18 +0000 (11:24 +0200)
If a referenced allocation is explicitly freed the new owner
should be the same as if the same allocation is implicitly freed
(e.g. because it's owner was freed).

Signed-off-by: Sam Liddicott <sam@liddicott.com>
lib/talloc/testsuite.c

index 13010030459152080eeca7447daa0e65da431c60..49070d9cbdbbd769075a60b6a2622bda22f1bdc5 100644 (file)
@@ -819,6 +819,71 @@ static bool test_unref_reparent(void)
        return true;
 }
 
+/* If a referenced allocation is explicitly freed the new owner
+   should be the same as if the same allocation is implicitly freed
+   (because it's owner was freed).
+   Traditionally in talloc an explicit free will free the top non-child reference
+   but an implicit free will move the top (any) reference to be the new owner */
+static bool test_implicit_explicit_free(void)
+{
+       void *root, *p1, *p2, *p3, *ref, *r1;
+       int e, i;
+
+       printf("test: test_implicit_explicit_free\n# SINGLE REFERENCE IMPLICIT FREE\n");
+
+       root = talloc_named_const(NULL, 0, "root");
+       p1 = talloc_named_const(root, 1, "p1");
+       p2 = talloc_named_const(p1, 1, "p2");
+       /* Now root owns p1, and p1 owns p2 */
+
+       r1 = talloc_named_const(root, 1, "r1");
+       ref = talloc_reference(r1, p2);
+       /* now r1 has ref reference to p2 */
+       talloc_report_full(root, stderr);
+
+       CHECK_BLOCKS(__FUNCTION__, p1, 2);
+       CHECK_BLOCKS(__FUNCTION__, p2, 1);
+       CHECK_BLOCKS(__FUNCTION__, r1, 2);
+
+       fprintf(stderr, "Freeing p2\n");
+       talloc_free(p2);
+       /* how many blocks is r1 taking against p2 ? */
+       e=talloc_total_blocks(r1);
+
+       talloc_report_full(root, stderr);
+       talloc_free(root);
+
+       /* now repeat, but this time free p1 */
+       printf("# SINGLE REFERENCE EXPLICIT FREE\n");
+
+       root = talloc_named_const(NULL, 0, "root");
+       p1 = talloc_named_const(root, 1, "p1");
+       p2 = talloc_named_const(p1, 1, "p2");
+       /* Now root owns p1, and p1 owns p2 */
+
+       r1 = talloc_named_const(root, 1, "r1");
+       ref = talloc_reference(r1, p2);
+       /* now r1 has ref reference to p2 */
+       talloc_report_full(NULL, stderr);
+
+       CHECK_BLOCKS(__FUNCTION__, p1, 2);
+       CHECK_BLOCKS(__FUNCTION__, p2, 1);
+       CHECK_BLOCKS(__FUNCTION__, r1, 2);
+
+       fprintf(stderr, "Freeing p1\n");
+       talloc_free(p1);
+       /* how many blocks is r1 taking against p2 ? */
+       i=talloc_total_blocks(r1);
+       talloc_report_full(NULL, stderr);
+
+       CHECK_BLOCKS(__FUNCTION__,r1, e);
+
+       talloc_free(root);
+
+       printf("success: ref1\n");
+       return true;
+}
+
 /*
   measure the speed of talloc versus malloc
 */
@@ -1203,6 +1268,8 @@ bool torture_local_talloc(struct torture_context *tctx)
        test_reset();
        ret &= test_talloc_free_in_destructor();
        test_reset();
+       ret &= test_implicit_explicit_free();
+       test_reset();
        ret &= test_pool();
 
        if (ret) {