You can now simply add per-tal-object helpers for memleak, but our older pattern required calling memleak functions explicitly during memleak handling. Hash tables in particular need to be dynamically allocated (we override the allocators using htable_set_allocator and assume this), so it makes sense to have a helper macro that does all three. This eliminates a huge amount of code. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
164 lines
5.3 KiB
C
164 lines
5.3 KiB
C
#ifndef LIGHTNING_COMMON_MEMLEAK_H
|
|
#define LIGHTNING_COMMON_MEMLEAK_H
|
|
#include "config.h"
|
|
#include <ccan/strmap/strmap.h>
|
|
#include <ccan/tal/tal.h>
|
|
|
|
struct htable;
|
|
struct list_head;
|
|
|
|
/**
|
|
* memleak_init: Initialize memleak detection; you call this at the start!
|
|
*
|
|
* notleak() won't have an effect if called before this (but naming
|
|
* tal objects with suffix _notleak works).
|
|
*/
|
|
void memleak_init(void);
|
|
|
|
/**
|
|
* notleak: remove a false-positive tal object.
|
|
* @p: the tal allocation.
|
|
*
|
|
* This marks a tal pointer (and anything it refers to) as not being
|
|
* leaked. Think hard before using this!
|
|
*/
|
|
#define notleak(p) ((memleak_typeof(p))notleak_((p), false))
|
|
|
|
/* Mark a pointer and all its tal children as not being leaked.
|
|
* You don't want this; it's for simplifying handling of the incoming
|
|
* command which asks lightningd to do the dev check. */
|
|
#define notleak_with_children(p) ((memleak_typeof(p))notleak_((p), true))
|
|
|
|
#if HAVE_TYPEOF
|
|
#define memleak_typeof(var) typeof(var)
|
|
#else
|
|
#define memleak_typeof(var) void *
|
|
#endif /* !HAVE_TYPEOF */
|
|
|
|
void *notleak_(void *ptr, bool plus_children);
|
|
|
|
/**
|
|
* memleak_add_helper: help memleak look inside this tal object
|
|
* @p: the tal object
|
|
* @cb: the callback.
|
|
*
|
|
* memleak looks for tal pointers inside a tal object memory, but some
|
|
* structures which use bit-stealing on pointers or use non-tal allocations
|
|
* will need this.
|
|
*
|
|
* The callback usually calls memleak_remove_*.
|
|
*/
|
|
#define memleak_add_helper(p, cb) \
|
|
memleak_add_helper_((p), \
|
|
typesafe_cb_preargs(void, const tal_t *, \
|
|
(cb), (p), \
|
|
struct htable *))
|
|
|
|
/* For update-mock: memleak_add_helper_ mock empty */
|
|
void memleak_add_helper_(const tal_t *p, void (*cb)(struct htable *memtable,
|
|
const tal_t *));
|
|
|
|
/**
|
|
* memleak_start: allocate a htable with all tal objects
|
|
* @ctx: the context to allocate the htable from
|
|
*/
|
|
struct htable *memleak_start(const tal_t *ctx);
|
|
|
|
/**
|
|
* memleak_ptr: this pointer is not a memleak.
|
|
* @memtable: the memtable create by memleak_start.
|
|
* @p: the pointer.
|
|
*
|
|
* This tells memleak that @p (a tal allocation) is not a leak. Returns
|
|
* true if it was in the memleak table (it will no longer be).
|
|
*/
|
|
bool memleak_ptr(struct htable *memtable, const void *p);
|
|
|
|
/**
|
|
* memleak_scan_obj - this tal object and anything it references are not leaks.
|
|
* @memtable: the memtable create by memleak_start.
|
|
* @obj: the tal pointer
|
|
*
|
|
* This removes @obj from the memtable, then looks for any tal pointers
|
|
* inside @obj and calls memleak_scan_obj() on those if not already removed.
|
|
*/
|
|
void memleak_scan_obj(struct htable *memtable, const void *obj);
|
|
|
|
/**
|
|
* memleak_scan_list_head - this list is not a leak.
|
|
* @memtable: the memtable create by memleak_start.
|
|
* @l: the list_head pointer
|
|
*
|
|
* This removes @l from the memtable, and any elements in the list. Usually
|
|
* used for file-scope linked lists.
|
|
*/
|
|
void memleak_scan_list_head(struct htable *memtable, const struct list_head *l);
|
|
|
|
/**
|
|
* memleak_scan_region - scan a non-tal allocation for references.
|
|
* @memtable: the memtable create by memleak_start.
|
|
* @p: the tal pointer
|
|
* @len: the length in bytes.
|
|
*
|
|
* Sometimes we have a stack or file-scope object which contains pointers.
|
|
*/
|
|
void memleak_scan_region(struct htable *memtable, const void *p, size_t len);
|
|
|
|
/* Objects inside this htable (which is opaque to memleak) are not leaks. */
|
|
void memleak_scan_htable(struct htable *memtable, const struct htable *ht);
|
|
|
|
/* Allocate a htable, set up memleak scan automatically (assumes &p->raw == p) */
|
|
#define new_htable(ctx, type) \
|
|
({ \
|
|
const struct htable *raw; \
|
|
struct type *p = tal(ctx, struct type); \
|
|
type##_init(p); \
|
|
raw = &p->raw; \
|
|
assert((void *)raw == (void *)p); \
|
|
memleak_add_helper(raw, memleak_scan_htable); \
|
|
p; \
|
|
})
|
|
|
|
/* Objects inside this uintmap (which is opaque to memleak) are not leaks. */
|
|
#define memleak_scan_uintmap(memtable, umap) \
|
|
memleak_scan_intmap_(memtable, uintmap_unwrap_(umap))
|
|
|
|
struct intmap;
|
|
void memleak_scan_intmap_(struct htable *memtable, const struct intmap *m);
|
|
|
|
/* Objects inside this strmap (which is opaque to memleak) are not leaks. */
|
|
#define memleak_scan_strmap(memtable, strmap) \
|
|
memleak_scan_strmap_((memtable), tcon_unwrap(strmap))
|
|
void memleak_scan_strmap_(struct htable *memtable, const struct strmap *m);
|
|
|
|
/**
|
|
* memleak_ignore_children - ignore all this tal object's children.
|
|
* @memtable: the memtable created by memleak_start
|
|
* @p: the tal pointer.
|
|
*
|
|
* This is equivalent to calling memleak_ptr() on every child of @p
|
|
* recursively. This is a big hammer, so be careful!
|
|
*/
|
|
void memleak_ignore_children(struct htable *memtable, const void *p);
|
|
|
|
/**
|
|
* dump_memleak: use print function to dump memleak details
|
|
* @memtable: the memtable after all known allocations removed.
|
|
* @print: the printf-style function to use (takes @arg first)
|
|
* @arg: the arg for @print
|
|
*
|
|
* Returns true if there was a leak.
|
|
*/
|
|
#define dump_memleak(memtable, print, arg) \
|
|
dump_memleak_((memtable), \
|
|
typesafe_cb_postargs(void, void *, (print), (arg), const char *, ...), \
|
|
(arg))
|
|
|
|
bool dump_memleak_(struct htable *memtable,
|
|
void PRINTF_FMT(2,3) (*print)(void *arg, const char *fmt, ...),
|
|
void *arg);
|
|
|
|
extern struct backtrace_state *backtrace_state;
|
|
|
|
#endif /* LIGHTNING_COMMON_MEMLEAK_H */
|