libplugin: forget pending requests if associated command freed.

This is usually fine, but without this, commando (another branch!) has
a race:

1. A command has multiple parts.
2. We start sending them out.
3. We get a response, which completes the cmd.
4. We go to send the next one out, but it's been freed.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2022-09-13 06:49:12 +09:30
parent bf54d6dcf5
commit 42c9aa1a5f

View File

@@ -173,6 +173,11 @@ static const char *get_json_id(const tal_t *ctx,
plugin->next_outreq_id++);
}
static void destroy_out_req(struct out_req *out_req, struct plugin *plugin)
{
strmap_del(&plugin->out_reqs, out_req->id, NULL);
}
/* FIXME: Move lightningd/jsonrpc to common/ ? */
struct out_req *
@@ -190,13 +195,14 @@ jsonrpc_request_start_(struct plugin *plugin, struct command *cmd,
{
struct out_req *out;
out = tal(plugin, struct out_req);
out = tal(cmd, struct out_req);
out->id = get_json_id(out, plugin, cmd ? cmd->id : NULL, method);
out->cmd = cmd;
out->cb = cb;
out->errcb = errcb;
out->arg = arg;
strmap_add(&plugin->out_reqs, out->id, out);
tal_add_destructor2(out, destroy_out_req, plugin);
/* If command goes away, don't call callbacks! */
if (out->cmd)
@@ -684,7 +690,6 @@ static void handle_rpc_reply(struct plugin *plugin, const jsmntok_t *toks)
/* We want to free this if callback doesn't. */
tal_steal(tmpctx, out);
strmap_del(&plugin->out_reqs, out->id, NULL);
contenttok = json_get_member(plugin->rpc_buffer, toks, "error");
if (contenttok) {