From 20fcb5d6ef8e6a8dd4d9851ac48f35973c308ada Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 15 Dec 2017 20:52:40 +1030 Subject: [PATCH] memleak: allow marking of entire tal trees to be noleak. In particular, the pay command attaches all kinds of stuff to the struct command; they're not really a leak, since commands expire. Signed-off-by: Rusty Russell --- common/memleak.c | 38 ++++++++++++++++++++++++++++---------- common/memleak.h | 7 +++++-- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/common/memleak.c b/common/memleak.c index 602eb9c29..d6d6d7d8d 100644 --- a/common/memleak.c +++ b/common/memleak.c @@ -9,6 +9,7 @@ #if DEVELOPER static struct backtrace_state *backtrace_state; static const void **notleaks; +static bool *notleak_children; static size_t find_notleak(const tal_t *ptr) { @@ -30,14 +31,18 @@ static void notleak_change(tal_t *ctx, i = find_notleak(ctx); memmove(notleaks + i, notleaks + i + 1, sizeof(*notleaks) * (tal_count(notleaks) - i - 1)); + memmove(notleak_children + i, notleak_children + i + 1, + sizeof(*notleak_children) + * (tal_count(notleak_children) - i - 1)); tal_resize(¬leaks, tal_count(notleaks) - 1); + tal_resize(¬leak_children, tal_count(notleak_children) - 1); } else if (type == TAL_NOTIFY_MOVE) { i = find_notleak(info); notleaks[i] = ctx; } } -void *notleak_(const void *ptr) +void *notleak_(const void *ptr, bool plus_children) { size_t nleaks; @@ -47,7 +52,9 @@ void *notleak_(const void *ptr) nleaks = tal_count(notleaks); tal_resize(¬leaks, nleaks+1); + tal_resize(¬leak_children, nleaks+1); notleaks[nleaks] = ptr; + notleak_children[nleaks] = plus_children; tal_add_notifier(ptr, TAL_NOTIFY_FREE|TAL_NOTIFY_MOVE, notleak_change); return cast_const(void *, ptr); @@ -130,23 +137,33 @@ void memleak_scan_region(struct htable *memtable, const void *ptr) scan_for_pointers(memtable, ptr); } +static void remove_with_children(struct htable *memtable, const tal_t *p) +{ + const tal_t *i; + + pointer_referenced(memtable, p); + for (i = tal_first(p); i; i = tal_next(i)) + remove_with_children(memtable, i); +} + void memleak_remove_referenced(struct htable *memtable, const void *root) { + size_t i; + /* Now delete the ones which are referenced. */ memleak_scan_region(memtable, root); memleak_scan_region(memtable, notleaks); - /* Remove memtable itself */ - pointer_referenced(memtable, memtable); -} + /* Those who asked tal children to be removed, do so. */ + for (i = 0; i < tal_count(notleaks); i++) + if (notleak_children[i]) + remove_with_children(memtable, notleaks[i]); -static void remove_with_children(struct htable *memtable, const tal_t *p) -{ - const tal_t *i; + /* notleak_children array is not a leak */ + pointer_referenced(memtable, notleak_children); - pointer_referenced(memtable, p); - for (i = tal_first(p); i; i = tal_next(i)) - remove_with_children(memtable, i); + /* Remove memtable itself */ + pointer_referenced(memtable, memtable); } static bool ptr_match(const void *candidate, void *ptr) @@ -214,6 +231,7 @@ void memleak_init(const tal_t *root, struct backtrace_state *bstate) assert(!notleaks); backtrace_state = bstate; notleaks = tal_arr(NULL, const void *, 0); + notleak_children = tal_arr(notleaks, bool, 0); if (backtrace_state) tal_add_notifier(root, TAL_NOTIFY_ADD_CHILD, add_backtrace); diff --git a/common/memleak.h b/common/memleak.h index cd990fb58..a06e17612 100644 --- a/common/memleak.h +++ b/common/memleak.h @@ -11,10 +11,13 @@ #endif /* !HAVE_TYPEOF */ /* Mark a pointer as not being leaked. */ -#define notleak(p) ((memleak_typeof(p))notleak_(p)) +#define notleak(p) ((memleak_typeof(p))notleak_((p), false)) + +/* Mark a pointer and all its tal children as not being leaked. */ +#define notleak_with_children(p) ((memleak_typeof(p))notleak_((p), true)) #if DEVELOPER -void *notleak_(const void *ptr); +void *notleak_(const void *ptr, bool plus_children); struct htable; struct backtrace_state;