-/* check that an allocation that is freed while also referenced finally goes
- away when the reference is released */
-static bool test_ref_free(void)
-{
- void *root, *p1, *p2, *ref, *r1;
-
- printf("test: test_ref_free\n# FREE ON SINGLE REFERENCE FREE\n");
- talloc_erase_no_owner_context();
-
- 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);
- /* r1 should have ref reference to p2 still */
- talloc_report_full(root, stderr);
-
- CHECK_BLOCKS(__FUNCTION__, p1, 1);
- CHECK_BLOCKS(__FUNCTION__, root, 4);
- CHECK_BLOCKS(__FUNCTION__, r1, 2);
-
- /* if we free r1 then p2 should also vanish */
- fprintf(stderr, "Freeing r1\n");
- talloc_free(r1);
- /* p2 should have gone away */
- talloc_report_full(NULL, stderr);
- CHECK_BLOCKS(__FUNCTION__, root, 2);
- CHECK_BLOCKS(__FUNCTION__, p1, 1);
-
- talloc_free(root);
- printf("success: ref1\n");
- return true;
-}
-
-/* If an object having references from children that are also referenced is
- freed, the child reference will be removed, but the child will survive
- (because of it's reference) and the object will still be freed leaving
- a dangling reference */
-static bool test_dangling_loop(void)
-{
- void *root, *p1, *p2, *ref, *r1, *r2;
-
- printf("test: %s\n# FREE ON SINGLE REFERENCE FREE\n",__FUNCTION__);
- talloc_erase_no_owner_context();
-
- 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 */
-
- /* someone takes a ref on p2 */
- r1 = talloc_named_const(root, 1, "r1");
- ref = talloc_reference(r1, p2);
-
- /* p2 takes a ref on p1 */
- talloc_reference(p2, p1);
-
- talloc_report_full(NULL, stderr);
-
- CHECK_BLOCKS(__FUNCTION__, root, 6);
- CHECK_BLOCKS(__FUNCTION__, p1, 3);
- CHECK_BLOCKS(__FUNCTION__, p2, 2);
- CHECK_BLOCKS(__FUNCTION__, r1, 2);
-
- /* talloc will wrongly spot a loop and free p2's ref, and then p1
- leaving a dangling pointer */
- fprintf(stderr, "Freeing p1\n");
- talloc_free(p1);
- /* p1 should not get freed as it is referenced from something (a child) that won't free */
- /* r1 should have ref reference to p2 still */
- talloc_report_full(NULL, stderr);
-
- CHECK_BLOCKS(__FUNCTION__, root, 3);
- /* The ugly talloc de-child-looping code will delete p2's reference
- leaving p2 having a dangling pointer. p2's reference should remain */
- CHECK_BLOCKS(__FUNCTION__, p2, 2);
- CHECK_BLOCKS(__FUNCTION__, r1, 2);
-
- /* if we free r1 then p2 should also vanish as it is owned by something that
- is not owned, but we can't track that yet. Once p2 vanishes it's reference
- to p1 should vanish letting p1 vanish.
- We can often make sub-tree's from no-owner-context, by checking when references
- of things child-of no-owner-context die
- */
- fprintf(stderr, "Freeing r1\n");
- talloc_free(r1);
- talloc_report_full(NULL, stderr);
- CHECK_BLOCKS(__FUNCTION__, root, 1);
-
- talloc_free(root);
- printf("success: ref1\n");
-
- talloc_erase_no_owner_context();
- talloc_report_full(NULL, stderr);
- return true;
-}
-