From d3ea9bf8bff9d1a13bb3e18f9a428dc9e51baa49 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 22 Nov 2018 12:47:29 +1030 Subject: [PATCH] channeld: wire up dev_memleak. Signed-off-by: Rusty Russell --- channeld/channel_wire.csv | 6 +++ channeld/channeld.c | 29 +++++++++- lightningd/channel_control.c | 2 + lightningd/memdump.c | 13 ++++- lightningd/memdump.h | 1 + lightningd/peer_control.c | 59 +++++++++++++++++++++ lightningd/peer_control.h | 5 ++ lightningd/test/run-invoice-select-inchan.c | 9 ++++ wallet/test/run-wallet.c | 9 ++++ 9 files changed, 130 insertions(+), 3 deletions(-) diff --git a/channeld/channel_wire.csv b/channeld/channel_wire.csv index a6c2b2a53..9c7d1bf62 100644 --- a/channeld/channel_wire.csv +++ b/channeld/channel_wire.csv @@ -166,6 +166,12 @@ channel_feerates,,feerate,u32 channel_feerates,,min_feerate,u32 channel_feerates,,max_feerate,u32 +# master -> channeld: do you have a memleak? +channel_dev_memleak,1033 + +channel_dev_memleak_reply,1133 +channel_dev_memleak_reply,,leak,bool + # Peer presented proof it was from the future. channel_fail_fallen_behind,1028 channel_fail_fallen_behind,,remote_per_commitment_point,struct pubkey diff --git a/channeld/channeld.c b/channeld/channeld.c index f95fc8e16..09b89092a 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -2470,7 +2471,24 @@ static void handle_dev_reenable_commit(struct peer *peer) wire_sync_write(MASTER_FD, take(towire_channel_dev_reenable_commit_reply(NULL))); } -#endif + +static void handle_dev_memleak(struct peer *peer, const u8 *msg) +{ + struct htable *memtable; + bool found_leak; + + memtable = memleak_enter_allocations(tmpctx, msg, msg); + + /* Now delete peer and things it has pointers to. */ + memleak_remove_referenced(memtable, peer); + memleak_remove_htable(memtable, &peer->channel->htlcs->raw); + + found_leak = dump_memleak(memtable); + wire_sync_write(MASTER_FD, + take(towire_channel_dev_memleak_reply(NULL, + found_leak))); +} +#endif /* DEVELOPER */ static void req_in(struct peer *peer, const u8 *msg) { @@ -2495,10 +2513,16 @@ static void req_in(struct peer *peer, const u8 *msg) case WIRE_CHANNEL_SEND_SHUTDOWN: handle_shutdown_cmd(peer, msg); return; - case WIRE_CHANNEL_DEV_REENABLE_COMMIT: #if DEVELOPER + case WIRE_CHANNEL_DEV_REENABLE_COMMIT: handle_dev_reenable_commit(peer); return; + case WIRE_CHANNEL_DEV_MEMLEAK: + handle_dev_memleak(peer, msg); + return; +#else + case WIRE_CHANNEL_DEV_REENABLE_COMMIT: + case WIRE_CHANNEL_DEV_MEMLEAK: #endif /* DEVELOPER */ case WIRE_CHANNEL_INIT: case WIRE_CHANNEL_OFFER_HTLC_REPLY: @@ -2513,6 +2537,7 @@ static void req_in(struct peer *peer, const u8 *msg) case WIRE_CHANNEL_SHUTDOWN_COMPLETE: case WIRE_CHANNEL_DEV_REENABLE_COMMIT_REPLY: case WIRE_CHANNEL_FAIL_FALLEN_BEHIND: + case WIRE_CHANNEL_DEV_MEMLEAK_REPLY: break; } master_badmsg(-1, msg); diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index cc354bf9d..b93e78dac 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -232,9 +232,11 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) case WIRE_CHANNEL_SEND_SHUTDOWN: case WIRE_CHANNEL_DEV_REENABLE_COMMIT: case WIRE_CHANNEL_FEERATES: + case WIRE_CHANNEL_DEV_MEMLEAK: /* Replies go to requests. */ case WIRE_CHANNEL_OFFER_HTLC_REPLY: case WIRE_CHANNEL_DEV_REENABLE_COMMIT_REPLY: + case WIRE_CHANNEL_DEV_MEMLEAK_REPLY: break; } diff --git a/lightningd/memdump.c b/lightningd/memdump.c index 8b7cba511..eb940d7ed 100644 --- a/lightningd/memdump.c +++ b/lightningd/memdump.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -255,7 +256,7 @@ static void hsm_dev_memleak_done(struct subd *hsmd, -1, 0, connect_dev_memleak_done, cmd); } -void opening_memleak_done(struct command *cmd, struct subd *leaker) +void peer_memleak_done(struct command *cmd, struct subd *leaker) { if (leaker) report_leak_info(cmd, leaker); @@ -271,6 +272,16 @@ void opening_memleak_done(struct command *cmd, struct subd *leaker) } } +void opening_memleak_done(struct command *cmd, struct subd *leaker) +{ + if (leaker) + report_leak_info(cmd, leaker); + else { + /* No leak there, try normal peers. */ + peer_dev_memleak(cmd); + } +} + static void json_memleak(struct command *cmd, const char *buffer UNNEEDED, const jsmntok_t *params UNNEEDED) diff --git a/lightningd/memdump.h b/lightningd/memdump.h index 88741a364..b7837d1b3 100644 --- a/lightningd/memdump.h +++ b/lightningd/memdump.h @@ -8,4 +8,5 @@ struct command; struct subd; void opening_memleak_done(struct command *cmd, struct subd *leaker); +void peer_memleak_done(struct command *cmd, struct subd *leaker); #endif /* LIGHTNING_LIGHTNINGD_MEMDUMP_H */ diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 1bc358a72..7939f002b 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -1395,5 +1396,63 @@ static const struct json_command dev_forget_channel_command = { "Forget the channel with peer {id}. Checks if the channel is still active by checking its funding transaction. Check can be ignored by setting {force} to 'true'" }; AUTODATA(json_command, &dev_forget_channel_command); + +/* Mutual recursion */ +static void peer_memleak_req_next(struct command *cmd, struct channel *prev); +static void channeld_memleak_req_done(struct subd *channeld, + const u8 *msg, const int *fds UNUSED, + struct command *cmd) +{ + struct channel *c = channeld->channel; + bool found_leak; + + if (!fromwire_channel_dev_memleak_reply(msg, &found_leak)) { + command_fail(cmd, LIGHTNINGD, "Bad channel_dev_memleak"); + return; + } + + if (found_leak) { + peer_memleak_done(cmd, channeld); + return; + } + peer_memleak_req_next(cmd, c); +} + +static void peer_memleak_req_next(struct command *cmd, struct channel *prev) +{ + struct peer *p; + + list_for_each(&cmd->ld->peers, p, list) { + struct channel *c; + + list_for_each(&p->channels, c, list) { + if (c == prev) { + prev = NULL; + continue; + } + + if (!c->owner) + continue; + + if (prev != NULL) + continue; + + /* FIXME: handle onchaind here */ + /* FIXME: handle closingd here */ + if (streq(c->owner->name, "lightning_channeld")) { + subd_req(c, c->owner, + take(towire_channel_dev_memleak(NULL)), + -1, 0, channeld_memleak_req_done, cmd); + return; + } + } + } + peer_memleak_done(cmd, NULL); +} + +void peer_dev_memleak(struct command *cmd) +{ + peer_memleak_req_next(cmd, NULL); +} #endif /* DEVELOPER */ diff --git a/lightningd/peer_control.h b/lightningd/peer_control.h index 5dc06d62d..6464a77e3 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -91,4 +91,9 @@ void channel_watch_funding(struct lightningd *ld, struct channel *channel); /* Pull peers, channels and HTLCs from db, and wire them up. */ void load_channels_from_wallet(struct lightningd *ld); + +#if DEVELOPER +void peer_dev_memleak(struct command *cmd); +#endif /* DEVELOPER */ + #endif /* LIGHTNING_LIGHTNINGD_PEER_CONTROL_H */ diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index c9eb7537d..c758fde1a 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -67,6 +67,9 @@ void delay_then_reconnect(struct channel *channel UNNEEDED, u32 seconds_delay UN /* Generated stub for fatal */ void fatal(const char *fmt UNNEEDED, ...) { fprintf(stderr, "fatal called!\n"); abort(); } +/* Generated stub for fromwire_channel_dev_memleak_reply */ +bool fromwire_channel_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED) +{ fprintf(stderr, "fromwire_channel_dev_memleak_reply called!\n"); abort(); } /* Generated stub for fromwire_connect_peer_connected */ bool fromwire_connect_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct pubkey *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct crypto_state *crypto_state UNNEEDED, u8 **globalfeatures UNNEEDED, u8 **localfeatures UNNEEDED) { fprintf(stderr, "fromwire_connect_peer_connected called!\n"); abort(); } @@ -303,6 +306,9 @@ void opening_peer_no_active_channels(struct peer *peer UNNEEDED) bool param(struct command *cmd UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t params[] UNNEEDED, ...) { fprintf(stderr, "param called!\n"); abort(); } +/* Generated stub for peer_memleak_done */ +void peer_memleak_done(struct command *cmd UNNEEDED, struct subd *leaker UNNEEDED) +{ fprintf(stderr, "peer_memleak_done called!\n"); abort(); } /* Generated stub for peer_start_channeld */ void peer_start_channeld(struct channel *channel UNNEEDED, const struct crypto_state *cs UNNEEDED, @@ -348,6 +354,9 @@ void subd_req_(const tal_t *ctx UNNEEDED, /* Generated stub for subd_send_msg */ void subd_send_msg(struct subd *sd UNNEEDED, const u8 *msg_out UNNEEDED) { fprintf(stderr, "subd_send_msg called!\n"); abort(); } +/* Generated stub for towire_channel_dev_memleak */ +u8 *towire_channel_dev_memleak(const tal_t *ctx UNNEEDED) +{ fprintf(stderr, "towire_channel_dev_memleak called!\n"); abort(); } /* Generated stub for towire_channel_dev_reenable_commit */ u8 *towire_channel_dev_reenable_commit(const tal_t *ctx UNNEEDED) { fprintf(stderr, "towire_channel_dev_reenable_commit called!\n"); abort(); } diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 2a85b753e..fab5a1204 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -70,6 +70,9 @@ void delay_then_reconnect(struct channel *channel UNNEEDED, u32 seconds_delay UN /* Generated stub for fatal */ void fatal(const char *fmt UNNEEDED, ...) { fprintf(stderr, "fatal called!\n"); abort(); } +/* Generated stub for fromwire_channel_dev_memleak_reply */ +bool fromwire_channel_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED) +{ fprintf(stderr, "fromwire_channel_dev_memleak_reply called!\n"); abort(); } /* Generated stub for fromwire_channel_got_commitsig */ bool fromwire_channel_got_commitsig(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u64 *commitnum UNNEEDED, u32 *feerate UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED, secp256k1_ecdsa_signature **htlc_signature UNNEEDED, struct added_htlc **added UNNEEDED, struct secret **shared_secret UNNEEDED, struct fulfilled_htlc **fulfilled UNNEEDED, struct failed_htlc ***failed UNNEEDED, struct changed_htlc **changed UNNEEDED, struct bitcoin_tx **tx UNNEEDED) { fprintf(stderr, "fromwire_channel_got_commitsig called!\n"); abort(); } @@ -353,6 +356,9 @@ void payment_store(struct lightningd *ld UNNEEDED, const struct sha256 *payment_ void payment_succeeded(struct lightningd *ld UNNEEDED, struct htlc_out *hout UNNEEDED, const struct preimage *rval UNNEEDED) { fprintf(stderr, "payment_succeeded called!\n"); abort(); } +/* Generated stub for peer_memleak_done */ +void peer_memleak_done(struct command *cmd UNNEEDED, struct subd *leaker UNNEEDED) +{ fprintf(stderr, "peer_memleak_done called!\n"); abort(); } /* Generated stub for peer_start_channeld */ void peer_start_channeld(struct channel *channel UNNEEDED, const struct crypto_state *cs UNNEEDED, @@ -401,6 +407,9 @@ void subd_req_(const tal_t *ctx UNNEEDED, /* Generated stub for subd_send_msg */ void subd_send_msg(struct subd *sd UNNEEDED, const u8 *msg_out UNNEEDED) { fprintf(stderr, "subd_send_msg called!\n"); abort(); } +/* Generated stub for towire_channel_dev_memleak */ +u8 *towire_channel_dev_memleak(const tal_t *ctx UNNEEDED) +{ fprintf(stderr, "towire_channel_dev_memleak called!\n"); abort(); } /* Generated stub for towire_channel_dev_reenable_commit */ u8 *towire_channel_dev_reenable_commit(const tal_t *ctx UNNEEDED) { fprintf(stderr, "towire_channel_dev_reenable_commit called!\n"); abort(); }