lightningd: fix occasional memleak when we detach subd from channel.
What changed, and why it matters
This commit fixes a false-positive memory leak report inside Core Lightning's internal process manager. When a background helper process (subdaemon) detaches from a payment channel, the cleanup can briefly leave the helper object without an obvious owner. The memory leak detector would flag this as a leak and crash the node in testing builds. The fix marks the object as 'not a leak' during this cleanup window. It is a reliability/debugging fix, not an exploitable security vulnerability.
No urgent security action. Treat as normal reliability/maintenance patch. If running builds with memleak detection, apply to avoid false-positive crashes. No advisory or CVE warranted based on the commit content.
Security signals we found
Memory-leak detector false positive in subdaemon lifecycle
No attacker-controlled input path identified
No memory corruption, privilege escalation, or remote code execution signal
Fix is defensive hardening of internal cleanup bookkeeping
Evidence from the diff
The change moves/adds notleak(sd) calls to the subd detach/cleanup paths in lightningd/subd.c (handle_peer_error and destroy_subd) and removes the previous notleak(owner) call in subd_release_channel. The reported memleak was a struct io_conn allocated in new_subd/new_channel_subd_ that transiently had no reachable parent while the subd was freeing itself. The fix suppresses the memleak warning during this cleanup phase. There is no evidence of memory corruption, use-after-free, or attacker-controlled behavior.
Changed components
lightningd/subd.csubdaemon lifecycle managementchannel owner detach pathInspect captured patch +4 / −5
diff --git a/lightningd/subd.c b/lightningd/subd.c
index 744d6152..05e08c08 100644
--- a/lightningd/subd.c
+++ b/lightningd/subd.c
@@ -438,6 +438,8 @@ static bool handle_peer_error(struct subd *sd, const u8 *msg, int fds[1])
/* Don't free sd; we may be about to free channel. */
sd->channel = NULL;
+ /* While it's cleaning up, this is not a leak! */
+ notleak(sd);
sd->errcb(channel, peer_fd, desc, err_for_them, disconnect, warning);
return true;
}
@@ -641,6 +643,8 @@ static void destroy_subd(struct subd *sd)
/* Clear any transient messages in billboard */
sd->billboardcb(channel, false, NULL);
+ /* While it's cleaning up, this is not a leak! */
+ notleak(sd);
sd->channel = NULL;
/* We can be freed both inside msg handling, or spontaneously. */
@@ -928,11 +932,6 @@ void subd_release_channel(struct subd *owner, const void *channel)
assert(owner->channel == channel);
owner->channel = NULL;
tal_free(owner);
- } else {
- /* Caller has reassigned channel->owner, so there's no pointer
- * to this subd owner while it's freeing itself. If we
- * ask memleak right now, it will complain! */
- notleak(owner);
}
}
Why this scored 19/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.