diff options
author | Andrew Tridgell <tridge@samba.org> | 2006-05-23 03:51:44 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 14:08:28 -0500 |
commit | 5da75f5c3631247615efdf73fae2481df6908cb8 (patch) | |
tree | 4eb12992cb255312ef70f0d8dafee7f65a8e9328 /source4/lib/talloc/talloc.c | |
parent | 495652fe24da009bdef839be9eb543837ecaab04 (diff) | |
download | samba-5da75f5c3631247615efdf73fae2481df6908cb8.tar.gz samba-5da75f5c3631247615efdf73fae2481df6908cb8.tar.bz2 samba-5da75f5c3631247615efdf73fae2481df6908cb8.zip |
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)
Diffstat (limited to 'source4/lib/talloc/talloc.c')
-rw-r--r-- | source4/lib/talloc/talloc.c | 36 |
1 files changed, 34 insertions, 2 deletions
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; } |