askrene: neated flow array handling, by freeing flows we discard.
What changed, and why it matters
This commit fixes a temporary memory leak in the askrene routing plugin of Core Lightning. When the code discarded unused payment routes (called 'flows'), it removed them from a list but forgot to free the memory they occupied. The commit adds a helper function that both removes and frees these discarded flows. The author notes it is a 'temporary leak' and a 'trap' for future developers, not an active security vulnerability.
No urgent security action required. The fix is a routine code-quality/memory-hygiene improvement. Operators should upgrade through normal release channels. If running a node with heavy payment routing, the fix reduces transient memory pressure but is not known to be exploitable.
Security signals we found
Memory leak in plugin routing code
Use-after-free risk avoided by consistent free-then-remove ordering
Temporary leak bounded by call context
No input validation, parsing, or cryptographic boundary crossed
Evidence from the diff
In plugins/askrene/refine.c, several call sites previously used tal_arr_remove() to drop struct flow pointers from a tal-allocated array. tal_arr_remove() shrinks the array but does not free the element itself, so the pointed-to struct flow (and anything it owns) was leaked until the array’s parent context was freed. The patch introduces del_flow_from_arr(), which calls tal_free() on the element before removing it. It also replaces a tal_resize(flows, num_parts) truncation with an explicit loop that frees each discarded tail element. The leak is bounded to the lifetime of the refine_flows()/reduce_num_flows() call context.
Changed components
plugins/askrene/refine.cdel_flow_from_arr helperremove_excess functionrefine_flows functionsquash_flows functionreduce_num_flows functionInspect captured patch +13 / −5
diff --git a/plugins/askrene/refine.c b/plugins/askrene/refine.c
index 3e2f9af8..1f30a4cb 100644
--- a/plugins/askrene/refine.c
+++ b/plugins/askrene/refine.c
@@ -312,6 +312,13 @@ static struct amount_msat sum_all_deliver(struct flow **flows)
return all_deliver;
}
+/* Remove and free the flow */
+static void del_flow_from_arr(struct flow ***flows, size_t i)
+{
+ tal_free((*flows)[i]);
+ tal_arr_remove(flows, i);
+}
+
/* It reduces the amount of the flows and/or removes some flows in order to
* deliver no more than max_deliver. It will leave at least one flow.
* Returns the total delivery amount. */
@@ -340,7 +347,7 @@ static struct amount_msat remove_excess(struct flow ***flows,
if (!amount_msat_deduct(&all_deliver,
(*flows)[i]->delivers))
abort();
- tal_arr_remove(flows, i);
+ del_flow_from_arr(flows, i);
}
/* If we still have some excess, remove it from the
@@ -511,7 +518,7 @@ const char *refine_flows(const tal_t *ctx, struct route_query *rq,
if (error_message)
goto fail;
/* htlc_min is not met for this flow */
- tal_arr_remove(flows, i);
+ del_flow_from_arr(flows, i);
}
/* remove 0 amount flows if any */
@@ -519,7 +526,7 @@ const char *refine_flows(const tal_t *ctx, struct route_query *rq,
for (int i = tal_count(*flows) - 1; i >= 0; i--) {
if (!amount_msat_is_zero((*flows)[i]->delivers))
break;
- tal_arr_remove(flows, i);
+ del_flow_from_arr(flows, i);
}
tal_free(working_ctx);
@@ -568,7 +575,7 @@ void squash_flows(const tal_t *ctx, struct route_query *rq,
if (amount_msat_greater(combined, max))
break;
flow->delivers = combined;
- tal_arr_remove(flows, i+1);
+ del_flow_from_arr(flows, i+1);
}
}
}
@@ -619,7 +626,8 @@ const char *reduce_num_flows(const tal_t *ctx,
*/
size_t orig_num_flows = tal_count(*flows);
asort(*flows, orig_num_flows, revcmp_flows, NULL);
- tal_resize(flows, num_parts);
+ while (tal_count(*flows) > num_parts)
+ del_flow_from_arr(flows, tal_count(*flows) - 1);
if (!increase_flows(rq, *flows, deliver, -1.0))
return rq_log(ctx, rq, LOG_INFORM,
Why this scored 25/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.