mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 09:54:16 +01:00
gossipd: wire up memleak detection.
For simplicity we dump leaks to logs, and just return a bool to master. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
78771ca371
commit
ab735dcbe6
@ -4,6 +4,7 @@
|
||||
#include <ccan/crypto/siphash24/siphash24.h>
|
||||
#include <ccan/htable/htable_type.h>
|
||||
#include <ccan/mem/mem.h>
|
||||
#include <common/memleak.h>
|
||||
#include <common/pseudorand.h>
|
||||
#include <common/status.h>
|
||||
#include <common/type_to_string.h>
|
||||
|
@ -35,4 +35,5 @@ const u8 *next_broadcast(struct broadcast_state *bstate,
|
||||
* NULL. */
|
||||
struct broadcast_state *broadcast_state_check(struct broadcast_state *b,
|
||||
const char *abortstr);
|
||||
|
||||
#endif /* LIGHTNING_GOSSIPD_BROADCAST_H */
|
||||
|
@ -135,6 +135,12 @@ gossip_outpoint_spent,,short_channel_id,struct short_channel_id
|
||||
# master -> gossipd: stop gossip timers.
|
||||
gossip_dev_suppress,3032
|
||||
|
||||
# master -> gossipd: do you have a memleak?
|
||||
gossip_dev_memleak,3033
|
||||
|
||||
gossip_dev_memleak_reply,3133
|
||||
gossip_dev_memleak_reply,,leak,bool
|
||||
|
||||
#include <common/bolt11.h>
|
||||
|
||||
# master -> gossipd: get route_info for our incoming channels
|
||||
|
|
@ -2342,6 +2342,26 @@ static struct io_plan *dev_gossip_suppress(struct io_conn *conn,
|
||||
suppress_gossip = true;
|
||||
return daemon_conn_read_next(conn, daemon->master);
|
||||
}
|
||||
|
||||
static struct io_plan *dev_gossip_memleak(struct io_conn *conn,
|
||||
struct daemon *daemon,
|
||||
const u8 *msg)
|
||||
{
|
||||
struct htable *memtable;
|
||||
bool found_leak;
|
||||
|
||||
memtable = memleak_enter_allocations(tmpctx, msg, msg);
|
||||
|
||||
/* Now delete daemon and those which it has pointers to. */
|
||||
memleak_remove_referenced(memtable, daemon);
|
||||
memleak_remove_routing_tables(memtable, daemon->rstate);
|
||||
|
||||
found_leak = dump_memleak(memtable);
|
||||
daemon_conn_send(daemon->master,
|
||||
take(towire_gossip_dev_memleak_reply(NULL,
|
||||
found_leak)));
|
||||
return daemon_conn_read_next(conn, daemon->master);
|
||||
}
|
||||
#endif /* DEVELOPER */
|
||||
|
||||
/*~ lightningd: so, tell me about this channel, so we can forward to it. */
|
||||
@ -2556,12 +2576,15 @@ static struct io_plan *recv_req(struct io_conn *conn,
|
||||
return dev_set_max_scids_encode_size(conn, daemon, msg);
|
||||
case WIRE_GOSSIP_DEV_SUPPRESS:
|
||||
return dev_gossip_suppress(conn, daemon, msg);
|
||||
case WIRE_GOSSIP_DEV_MEMLEAK:
|
||||
return dev_gossip_memleak(conn, daemon, msg);
|
||||
#else
|
||||
case WIRE_GOSSIP_QUERY_SCIDS:
|
||||
case WIRE_GOSSIP_SEND_TIMESTAMP_FILTER:
|
||||
case WIRE_GOSSIP_QUERY_CHANNEL_RANGE:
|
||||
case WIRE_GOSSIP_DEV_SET_MAX_SCIDS_ENCODE_SIZE:
|
||||
case WIRE_GOSSIP_DEV_SUPPRESS:
|
||||
case WIRE_GOSSIP_DEV_MEMLEAK:
|
||||
break;
|
||||
#endif /* !DEVELOPER */
|
||||
|
||||
@ -2575,6 +2598,7 @@ static struct io_plan *recv_req(struct io_conn *conn,
|
||||
case WIRE_GOSSIP_GET_CHANNEL_PEER_REPLY:
|
||||
case WIRE_GOSSIP_GET_INCOMING_CHANNELS_REPLY:
|
||||
case WIRE_GOSSIP_GET_TXOUT:
|
||||
case WIRE_GOSSIP_DEV_MEMLEAK_REPLY:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <ccan/mem/mem.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/features.h>
|
||||
#include <common/memleak.h>
|
||||
#include <common/pseudorand.h>
|
||||
#include <common/status.h>
|
||||
#include <common/type_to_string.h>
|
||||
@ -1715,6 +1716,16 @@ void route_prune(struct routing_state *rstate)
|
||||
tal_free(pruned);
|
||||
}
|
||||
|
||||
#if DEVELOPER
|
||||
void memleak_remove_routing_tables(struct htable *memtable,
|
||||
const struct routing_state *rstate)
|
||||
{
|
||||
memleak_remove_htable(memtable, &rstate->nodes->raw);
|
||||
memleak_remove_htable(memtable, &rstate->pending_node_map->raw);
|
||||
memleak_remove_uintmap(memtable, &rstate->broadcasts->broadcasts);
|
||||
}
|
||||
#endif /* DEVELOPER */
|
||||
|
||||
bool handle_local_add_channel(struct routing_state *rstate, const u8 *msg)
|
||||
{
|
||||
struct short_channel_id scid;
|
||||
|
@ -327,4 +327,8 @@ bool routing_add_node_announcement(struct routing_state *rstate,
|
||||
*/
|
||||
bool handle_local_add_channel(struct routing_state *rstate, const u8 *msg);
|
||||
|
||||
#if DEVELOPER
|
||||
void memleak_remove_routing_tables(struct htable *memtable,
|
||||
const struct routing_state *rstate);
|
||||
#endif
|
||||
#endif /* LIGHTNING_GOSSIPD_ROUTING_H */
|
||||
|
@ -140,6 +140,15 @@ const char *wire_type_name(int e UNNEEDED)
|
||||
{ fprintf(stderr, "wire_type_name called!\n"); abort(); }
|
||||
/* AUTOGENERATED MOCKS END */
|
||||
|
||||
#if DEVELOPER
|
||||
/* Generated stub for memleak_remove_htable */
|
||||
void memleak_remove_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED)
|
||||
{ fprintf(stderr, "memleak_remove_htable called!\n"); abort(); }
|
||||
/* Generated stub for memleak_remove_intmap_ */
|
||||
void memleak_remove_intmap_(struct htable *memtable UNNEEDED, const struct intmap *m UNNEEDED)
|
||||
{ fprintf(stderr, "memleak_remove_intmap_ called!\n"); abort(); }
|
||||
#endif
|
||||
|
||||
/* Updates existing route if required. */
|
||||
static void add_connection(struct routing_state *rstate,
|
||||
const struct pubkey *from,
|
||||
|
@ -104,6 +104,15 @@ const char *wire_type_name(int e UNNEEDED)
|
||||
{ fprintf(stderr, "wire_type_name called!\n"); abort(); }
|
||||
/* AUTOGENERATED MOCKS END */
|
||||
|
||||
#if DEVELOPER
|
||||
/* Generated stub for memleak_remove_htable */
|
||||
void memleak_remove_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED)
|
||||
{ fprintf(stderr, "memleak_remove_htable called!\n"); abort(); }
|
||||
/* Generated stub for memleak_remove_intmap_ */
|
||||
void memleak_remove_intmap_(struct htable *memtable UNNEEDED, const struct intmap *m UNNEEDED)
|
||||
{ fprintf(stderr, "memleak_remove_intmap_ called!\n"); abort(); }
|
||||
#endif
|
||||
|
||||
const void *trc;
|
||||
|
||||
static struct half_chan *
|
||||
|
@ -102,6 +102,15 @@ const char *wire_type_name(int e UNNEEDED)
|
||||
{ fprintf(stderr, "wire_type_name called!\n"); abort(); }
|
||||
/* AUTOGENERATED MOCKS END */
|
||||
|
||||
#if DEVELOPER
|
||||
/* Generated stub for memleak_remove_htable */
|
||||
void memleak_remove_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED)
|
||||
{ fprintf(stderr, "memleak_remove_htable called!\n"); abort(); }
|
||||
/* Generated stub for memleak_remove_intmap_ */
|
||||
void memleak_remove_intmap_(struct htable *memtable UNNEEDED, const struct intmap *m UNNEEDED)
|
||||
{ fprintf(stderr, "memleak_remove_intmap_ called!\n"); abort(); }
|
||||
#endif
|
||||
|
||||
/* Updates existing route if required. */
|
||||
static void add_connection(struct routing_state *rstate,
|
||||
const struct pubkey *from,
|
||||
|
@ -118,6 +118,7 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
|
||||
case WIRE_GOSSIP_DEV_SET_MAX_SCIDS_ENCODE_SIZE:
|
||||
case WIRE_GOSSIP_DEV_SUPPRESS:
|
||||
case WIRE_GOSSIP_LOCAL_CHANNEL_CLOSE:
|
||||
case WIRE_GOSSIP_DEV_MEMLEAK:
|
||||
/* This is a reply, so never gets through to here. */
|
||||
case WIRE_GOSSIP_GETNODES_REPLY:
|
||||
case WIRE_GOSSIP_GETROUTE_REPLY:
|
||||
@ -126,6 +127,7 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
|
||||
case WIRE_GOSSIP_QUERY_CHANNEL_RANGE_REPLY:
|
||||
case WIRE_GOSSIP_GET_CHANNEL_PEER_REPLY:
|
||||
case WIRE_GOSSIP_GET_INCOMING_CHANNELS_REPLY:
|
||||
case WIRE_GOSSIP_DEV_MEMLEAK_REPLY:
|
||||
break;
|
||||
|
||||
case WIRE_GOSSIP_PING_REPLY:
|
||||
|
@ -5,12 +5,15 @@
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/daemon.h>
|
||||
#include <common/memleak.h>
|
||||
#include <common/timeout.h>
|
||||
#include <gossipd/gen_gossip_wire.h>
|
||||
#include <lightningd/chaintopology.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/jsonrpc_errors.h>
|
||||
#include <lightningd/lightningd.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <lightningd/param.h>
|
||||
#include <lightningd/subd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void json_add_ptr(struct json_stream *response, const char *name,
|
||||
@ -111,7 +114,8 @@ static void json_add_backtrace(struct json_stream *response,
|
||||
|
||||
static void scan_mem(struct command *cmd,
|
||||
struct json_stream *response,
|
||||
struct lightningd *ld)
|
||||
struct lightningd *ld,
|
||||
const struct subd *leaking_subd)
|
||||
{
|
||||
struct htable *memtable;
|
||||
const tal_t *i;
|
||||
@ -147,14 +151,64 @@ static void scan_mem(struct command *cmd,
|
||||
json_array_end(response);
|
||||
json_object_end(response);
|
||||
}
|
||||
|
||||
if (leaking_subd) {
|
||||
json_object_start(response, NULL);
|
||||
json_add_string(response, "subdaemon", leaking_subd->name);
|
||||
json_object_end(response);
|
||||
}
|
||||
json_array_end(response);
|
||||
}
|
||||
|
||||
struct leak_info {
|
||||
struct command *cmd;
|
||||
struct subd *leaker;
|
||||
};
|
||||
|
||||
static void report_leak_info2(struct leak_info *leak_info)
|
||||
{
|
||||
struct json_stream *response = json_stream_success(leak_info->cmd);
|
||||
|
||||
json_object_start(response, NULL);
|
||||
scan_mem(leak_info->cmd, response, leak_info->cmd->ld, leak_info->leaker);
|
||||
json_object_end(response);
|
||||
|
||||
command_success(leak_info->cmd, response);
|
||||
}
|
||||
|
||||
static void report_leak_info(struct command *cmd, struct subd *leaker)
|
||||
{
|
||||
struct leak_info *leak_info = tal(cmd, struct leak_info);
|
||||
|
||||
leak_info->cmd = cmd;
|
||||
leak_info->leaker = leaker;
|
||||
|
||||
/* Leak detection in a reply handler thinks we're leaking conn. */
|
||||
notleak(new_reltimer(&leak_info->cmd->ld->timers, leak_info->cmd,
|
||||
time_from_sec(0),
|
||||
report_leak_info2, leak_info));
|
||||
}
|
||||
|
||||
static void gossip_dev_memleak_done(struct subd *gossipd,
|
||||
const u8 *reply,
|
||||
const int *fds UNUSED,
|
||||
struct command *cmd)
|
||||
{
|
||||
bool found_leak;
|
||||
|
||||
if (!fromwire_gossip_dev_memleak_reply(reply, &found_leak)) {
|
||||
command_fail(cmd, LIGHTNINGD, "Bad gossip_dev_memleak");
|
||||
return;
|
||||
}
|
||||
|
||||
report_leak_info(cmd, found_leak ? gossipd : NULL);
|
||||
}
|
||||
|
||||
static void json_memleak(struct command *cmd,
|
||||
const char *buffer UNNEEDED,
|
||||
const jsmntok_t *params UNNEEDED)
|
||||
{
|
||||
struct json_stream *response;
|
||||
struct lightningd *ld = cmd->ld;
|
||||
|
||||
if (!param(cmd, buffer, params, NULL))
|
||||
return;
|
||||
@ -165,12 +219,9 @@ static void json_memleak(struct command *cmd,
|
||||
return;
|
||||
}
|
||||
|
||||
response = json_stream_success(cmd);
|
||||
json_object_start(response, NULL);
|
||||
scan_mem(cmd, response, cmd->ld);
|
||||
json_object_end(response);
|
||||
|
||||
command_success(cmd, response);
|
||||
subd_req(ld->gossip, ld->gossip, take(towire_gossip_dev_memleak(NULL)),
|
||||
-1, 0, gossip_dev_memleak_done, cmd);
|
||||
command_still_pending(cmd);
|
||||
}
|
||||
|
||||
static const struct json_command dev_memleak_command = {
|
||||
|
Loading…
Reference in New Issue
Block a user