talloc_stack: Call talloc destructors while frame is still around
authorVolker Lendecke <vl@samba.org>
Fri, 22 Jun 2018 14:25:10 +0000 (16:25 +0200)
committerJeremy Allison <jra@samba.org>
Sat, 23 Jun 2018 02:56:44 +0000 (04:56 +0200)
This fixes "samba-tool ntacl set -d10"

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Sat Jun 23 04:56:44 CEST 2018 on sn-devel-144

lib/util/talloc_stack.c

index 9c72c801197b2b8f4bcd7fd7627957a4702a700d..4971150e0d5ca8ac056239adde15b3b05661ac27 100644 (file)
@@ -94,6 +94,7 @@ static int talloc_pop(TALLOC_CTX *frame)
 {
        struct talloc_stackframe *ts =
                (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
+       size_t blocks;
        int i;
 
        /* Catch lazy frame-freeing. */
@@ -107,6 +108,34 @@ static int talloc_pop(TALLOC_CTX *frame)
 #endif
        }
 
+       for (i=0; i<10; i++) {
+
+               /*
+                * We have to free our children first, calling all
+                * destructors. If a destructor hanging deeply off
+                * "frame" uses talloc_tos() itself while freeing the
+                * toplevel frame, we panic because that nested
+                * talloc_tos() in the destructor does not find a
+                * stackframe anymore.
+                *
+                * Do it in a loop up to 10 times as the destructors
+                * might use more of talloc_tos().
+                */
+
+               talloc_free_children(frame);
+
+               blocks = talloc_total_blocks(frame);
+               if (blocks == 1) {
+                       break;
+               }
+       }
+
+       if (blocks != 1) {
+               DBG_WARNING("Left %zu blocks after %i "
+                           "talloc_free_children(frame) calls\n",
+                           blocks, i);
+       }
+
        for (i=ts->talloc_stacksize-1; i>0; i--) {
                if (frame == ts->talloc_stack[i]) {
                        break;