Make explicit free behave the same as implicit free
authorSam Liddicott <sam@liddicott.com>
Mon, 2 Feb 2009 12:12:07 +0000 (12:12 +0000)
committerStefan Metzmacher <metze@samba.org>
Thu, 9 Jul 2009 08:35:39 +0000 (10:35 +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).

Previously in talloc an explicit free will remove the top non-child reference
but an implicit free will move the top (any) reference to be the new owner

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

index 3d490ddf49319139093893caff827c9fd0346bc6..c56cef40e0dfdab5d9e85ed10e5ea4ad5cbaa14a 100644 (file)
@@ -784,6 +784,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("test: test_implicit_explicit_free\n# 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
 */
@@ -1132,6 +1197,7 @@ bool torture_local_talloc(struct torture_context *tctx)
        ret &= test_talloc_ptrtype();
        ret &= test_talloc_free_in_destructor();
        ret &= test_pool();
+       ret &= test_implicit_explicit_free();
 
        if (ret) {
                ret &= test_speed();