Revert "talloc: ensure the sibling linked list remains valid during a free"
authorStefan Metzmacher <metze@samba.org>
Tue, 9 Aug 2011 07:23:31 +0000 (09:23 +0200)
committerStefan Metzmacher <metze@samba.org>
Thu, 17 May 2018 08:12:19 +0000 (10:12 +0200)
This reverts commit cf986f200804ce873b43c1ecf2d5e1bd08eb8a25.

WAS e820d7da6796b5adc72f15d940abc53bc00b9b29

lib/talloc/talloc.c

index c8a913ab1eb7a7efccb22c63ccbe768ef2542a0d..4168b74dcee881341fa43699bc63179bc727987c 100644 (file)
@@ -1155,7 +1155,6 @@ static inline int _tc_free_internal(struct talloc_chunk *tc,
        } else {
                if (tc->prev) tc->prev->next = tc->next;
                if (tc->next) tc->next->prev = tc->prev;
-               tc->prev = tc->next = NULL;
        }
 
        tc->flags |= TALLOC_FLAG_LOOP;
@@ -1294,7 +1293,6 @@ static void *_talloc_steal_internal(const void *new_ctx, const void *ptr)
        } else {
                if (tc->prev) tc->prev->next = tc->next;
                if (tc->next) tc->next->prev = tc->prev;
-               tc->prev = tc->next = NULL;
        }
 
        tc->parent = new_tc;
@@ -1643,6 +1641,20 @@ static inline void _tc_free_children_internal(struct talloc_chunk *tc,
                        struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
                        if (p) new_parent = TC_PTR_FROM_CHUNK(p);
                }
+               /* finding the parent here is potentially quite
+                  expensive, but the alternative, which is to change
+                  talloc to always have a valid tc->parent pointer,
+                  makes realloc more expensive where there are a
+                  large number of children.
+
+                  The reason we need the parent pointer here is that
+                  if _talloc_free_internal() fails due to references
+                  or a failing destructor we need to re-parent, but
+                  the free call can invalidate the prev pointer.
+               */
+               if (new_parent == null_context && (tc->child->refs || tc->child->destructor)) {
+                       old_parent = talloc_parent_chunk(ptr);
+               }
                if (unlikely(_tc_free_internal(tc->child, location) == -1)) {
                        if (talloc_parent_chunk(child) != tc) {
                                /*
@@ -1652,7 +1664,7 @@ static inline void _tc_free_children_internal(struct talloc_chunk *tc,
                                continue;
                        }
                        if (new_parent == null_context) {
-                               struct talloc_chunk *p = talloc_parent_chunk(ptr);
+                               struct talloc_chunk *p = old_parent;
                                if (p) new_parent = TC_PTR_FROM_CHUNK(p);
                        }
                        _talloc_steal_internal(new_parent, child);