diff options
author | Stefan Metzmacher <metze@samba.org> | 2011-04-08 12:30:46 +0200 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2011-05-17 09:46:04 +0200 |
commit | 38633c9f0b7f86673f08903999583ad5b62c3548 (patch) | |
tree | 3d9e6e4db447c05e126150e5b3ec960052793141 | |
parent | f3b855d2ff9576715afe50d75678829c6bc0842d (diff) | |
download | samba-38633c9f0b7f86673f08903999583ad5b62c3548.tar.gz samba-38633c9f0b7f86673f08903999583ad5b62c3548.tar.bz2 samba-38633c9f0b7f86673f08903999583ad5b62c3548.zip |
talloc: fixed a use after free error in talloc_free_children()
This is similar to commit 6f51a1f45bf4de062cce7a562477e8140630a53d.
metze
-rw-r--r-- | lib/talloc/talloc.c | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 31308589af..8333f41c07 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -1287,13 +1287,28 @@ _PUBLIC_ void talloc_free_children(void *ptr) final choice is the null context. */ void *child = TC_PTR_FROM_CHUNK(tc->child); const void *new_parent = null_context; + struct talloc_chunk *old_parent = NULL; if (unlikely(tc->child->refs)) { 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(_talloc_free_internal(child, __location__) == -1)) { 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); |