The branch, master has been updated
       via  6b0cece lib: talloc: Test suite for the new destructor reparent 
logic.
       via  cc4e548 lib: talloc: Allow destructors to reparent the object 
they're called on.
       via  3289a5d lib: talloc: Fix bug when calling a destructor.
      from  e53f6e9 Add the definition of FSCTL_SET_INTEGRITY_INFORMATION found 
from a capture and the Web.

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 6b0cecee1b864a0589836caf9f5f2892f8cb6926
Author: Jeremy Allison <[email protected]>
Date:   Tue Mar 3 17:12:32 2015 -0800

    lib: talloc: Test suite for the new destructor reparent logic.
    
    Signed-off-by: Jeremy Allison <[email protected]>
    Reviewed-by: Volker Lendecke <[email protected]>
    Reviewed-by: Ira Cooper <[email protected]>
    
    Autobuild-User(master): Jeremy Allison <[email protected]>
    Autobuild-Date(master): Sun Mar  8 20:52:43 CET 2015 on sn-devel-104

commit cc4e5481ea060db7f6d8a83619d859b2e002eb90
Author: Jeremy Allison <[email protected]>
Date:   Tue Mar 3 17:02:47 2015 -0800

    lib: talloc: Allow destructors to reparent the object they're called on.
    
    If a destructor returns failure (-1) when freeing a child, talloc
    must then reparent the child.
    
    Firstly it tries the owner of any reference, next the parent of the
    current object calling _talloc_free_children_internal(), and finally
    the null context in the last resort.
    
    If a destructor reparented its own object, which can be a very
    desirable thing to do (a destructor can make a decision it isn't
    time to die yet, and as the parent may be going away it might
    want to move itself to longer-term storage) then this new parent
    gets overwritten by the existing reparenting logic.
    
    This patch checks when freeing a child if it already reparented
    itself, and if it did doesn't then overwrite the new parent.
    
    Makes destructors more flexible.
    
    Signed-off-by: Jeremy Allison <[email protected]>
    Reviewed-by: Volker Lendecke <[email protected]>
    Reviewed-by: Ira Cooper <[email protected]>

commit 3289a5d84f73bf044e5767a6c47a3f7bf8357c08
Author: Jeremy Allison <[email protected]>
Date:   Thu Mar 5 12:48:47 2015 -0800

    lib: talloc: Fix bug when calling a destructor.
    
    If the destructor itself calls talloc_set_destructor()
    and returns -1, the new destructor set is overwritten
    by talloc.
    
    Dectect that and leave the new destructor in place.
    
    Signed-off-by: Jeremy Allison <[email protected]>
    Reviewed-by: Ira Cooper <[email protected]>

-----------------------------------------------------------------------

Summary of changes:
 lib/talloc/talloc.c    | 15 ++++++++-
 lib/talloc/testsuite.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 96 insertions(+), 1 deletion(-)


Changeset truncated at 500 lines:

diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index fa56ea5..46f10f4 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -991,7 +991,13 @@ static inline int _talloc_free_internal(void *ptr, const 
char *location)
                }
                tc->destructor = (talloc_destructor_t)-1;
                if (d(ptr) == -1) {
-                       tc->destructor = d;
+                       /*
+                        * Only replace the destructor pointer if
+                        * calling the destructor didn't modify it.
+                        */
+                       if (tc->destructor == (talloc_destructor_t)-1) {
+                               tc->destructor = d;
+                       }
                        return -1;
                }
                tc->destructor = NULL;
@@ -1464,6 +1470,13 @@ static inline void _talloc_free_children_internal(struct 
talloc_chunk *tc,
                        if (p) new_parent = TC_PTR_FROM_CHUNK(p);
                }
                if (unlikely(_talloc_free_internal(child, location) == -1)) {
+                       if (talloc_parent_chunk(child) != tc) {
+                               /*
+                                * Destructor already reparented this child.
+                                * No further reparenting needed.
+                                */
+                               return;
+                       }
                        if (new_parent == null_context) {
                                struct talloc_chunk *p = 
talloc_parent_chunk(ptr);
                                if (p) new_parent = TC_PTR_FROM_CHUNK(p);
diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c
index a878278..eb3e13d 100644
--- a/lib/talloc/testsuite.c
+++ b/lib/talloc/testsuite.c
@@ -981,6 +981,84 @@ static bool test_free_parent_deny_child(void)
        return true;
 }
 
+struct new_parent {
+       void *new_parent;
+       char val[20];
+};
+
+static int reparenting_destructor(struct new_parent *np)
+{
+       talloc_set_destructor(np, NULL);
+       (void)talloc_move(np->new_parent, &np);
+       return -1;
+}
+
+static bool test_free_parent_reparent_child(void)
+{
+       void *top = talloc_new(NULL);
+       char *level1;
+       char *alternate_level1;
+       char *level2;
+       struct new_parent *level3;
+
+       printf("test: free_parent_reparent_child\n# "
+               "TALLOC FREE PARENT REPARENT CHILD\n");
+
+       level1 = talloc_strdup(top, "level1");
+       alternate_level1 = talloc_strdup(top, "alternate_level1");
+       level2 = talloc_strdup(level1, "level2");
+       level3 = talloc(level2, struct new_parent);
+       level3->new_parent = alternate_level1;
+       memset(level3->val, 'x', sizeof(level3->val));
+
+       talloc_set_destructor(level3, reparenting_destructor);
+       talloc_free(level1);
+
+       CHECK_PARENT("free_parent_reparent_child",
+               level3, alternate_level1);
+
+       talloc_free(top);
+
+       printf("success: free_parent_reparent_child\n");
+       return true;
+}
+
+static bool test_free_parent_reparent_child_in_pool(void)
+{
+       void *top = talloc_new(NULL);
+       char *level1;
+       char *alternate_level1;
+       char *level2;
+       void *pool;
+       struct new_parent *level3;
+
+       printf("test: free_parent_reparent_child_in_pool\n# "
+               "TALLOC FREE PARENT REPARENT CHILD IN POOL\n");
+
+       pool = talloc_pool(top, 1024);
+       level1 = talloc_strdup(pool, "level1");
+       alternate_level1 = talloc_strdup(top, "alternate_level1");
+       level2 = talloc_strdup(level1, "level2");
+       level3 = talloc(level2, struct new_parent);
+       level3->new_parent = alternate_level1;
+       memset(level3->val, 'x', sizeof(level3->val));
+
+       talloc_set_destructor(level3, reparenting_destructor);
+       talloc_free(level1);
+       talloc_set_destructor(level3, NULL);
+
+       CHECK_PARENT("free_parent_reparent_child_in_pool",
+               level3, alternate_level1);
+
+       /* Even freeing alternate_level1 should leave pool alone. */
+       talloc_free(alternate_level1);
+       talloc_free(top);
+
+       printf("success: free_parent_reparent_child_in_pool\n");
+       return true;
+}
+
+
 static bool test_talloc_ptrtype(void)
 {
        void *top = talloc_new(NULL);
@@ -1674,6 +1752,10 @@ bool torture_local_talloc(struct torture_context *tctx)
        test_reset();
        ret &= test_free_parent_deny_child(); 
        test_reset();
+       ret &= test_free_parent_reparent_child();
+       test_reset();
+       ret &= test_free_parent_reparent_child_in_pool();
+       test_reset();
        ret &= test_talloc_ptrtype();
        test_reset();
        ret &= test_talloc_free_in_destructor();


-- 
Samba Shared Repository

Reply via email to