From 5da75f5c3631247615efdf73fae2481df6908cb8 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 23 May 2006 03:51:44 +0000 Subject: r15824: fixed a subtle talloc bug to do with memory context loops. When you have a structure that references one of its parents, and a parent of that parent is freed, then the whole structure should be freed, not just the reference. this was found by the change notify code, as a side effect of fixing the memory leak yesterday (This used to be commit 70531dcaeeb9314d410baa0d285df6a265311541) --- source4/lib/talloc/talloc.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) (limited to 'source4/lib/talloc/talloc.c') diff --git a/source4/lib/talloc/talloc.c b/source4/lib/talloc/talloc.c index 8f046a02b8..823ae4ffb3 100644 --- a/source4/lib/talloc/talloc.c +++ b/source4/lib/talloc/talloc.c @@ -542,7 +542,13 @@ int talloc_free(void *ptr) tc = talloc_chunk_from_ptr(ptr); if (tc->refs) { + int is_child; + struct talloc_reference_handle *handle = tc->refs; + is_child = talloc_is_parent(handle, handle->ptr); talloc_reference_destructor(tc->refs); + if (is_child) { + return talloc_free(ptr); + } return -1; } @@ -1197,7 +1203,9 @@ void *talloc_find_parent_byname(const void *context, const char *name) return TC_PTR_FROM_CHUNK(tc); } while (tc && tc->prev) tc = tc->prev; - tc = tc->parent; + if (tc) { + tc = tc->parent; + } } return NULL; } @@ -1219,6 +1227,30 @@ void talloc_show_parents(const void *context, FILE *file) while (tc) { fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc))); while (tc && tc->prev) tc = tc->prev; - tc = tc->parent; + if (tc) { + tc = tc->parent; + } + } +} + +/* + return 1 if ptr is a parent of context +*/ +int talloc_is_parent(const void *context, const char *ptr) +{ + struct talloc_chunk *tc; + + if (context == NULL) { + return 0; + } + + tc = talloc_chunk_from_ptr(context); + while (tc) { + if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1; + while (tc && tc->prev) tc = tc->prev; + if (tc) { + tc = tc->parent; + } } + return 0; } -- cgit