Repository navigation
Conversation
… hidden DarwinProcess_scanThreads() early-continues when hideUserlandThreads is set, before the newly constructed Process/DarwinProcess reaches ProcessTable_add(). For a thread ID never seen before, this leaves the freshly xCalloc'd object unreferenced by the table: it is never found by a later scan (so a new one is allocated every cycle) and never reachable by Table_cleanupEntries (so it is never freed). Each refresh cycle leaks one Process object per never-before-seen thread while "Hide userland process threads" is enabled. linux/LinuxProcessTable.c avoids this by guarding its equivalent hide-branch with `preExisting &&`, so a thread is always registered on first sight before being hidden on later scans. Mirror that intent here with a minimal change: register the object via ProcessTable_add() before continuing, rather than restructuring the scan order to match Linux exactly. Found by code review while investigating an unrelated, still-unexplained ~2GB physical-footprint growth (~3.3M live malloc allocations via vmmap) on a long-running htop instance with hide_userland_threads=0 -- so this bug is confirmed present but was NOT the cause of that specific growth. It is a distinct, real leak that reproduces whenever "Hide userland process threads" is enabled. See tracking issue for full diagnostics on both. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Advanced Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review. 📝 WalkthroughWalkthroughWhen Suggested reviewers: Priority: ⬇️ Low Change: Bug fix Merge Risk: ⚪ Minimal · up to Newly discovered hidden threads remain tracked and can be reclaimed when they disappear. No actionable merge-blocking risk is established; the change is ready for normal checks. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Hidden threads join the table Comment |
Independent code-reviewer dispositionFindings from the independent review:
No code changes needed. This PR is otherwise ready for real review whenever the soak test has run long enough. |
|
Closing -- opened prematurely without the fork owner's authorization to submit upstream yet. Apologies for the noise. |
Summary
DarwinProcess_scanThreads()leaks oneProcess/DarwinProcessobject pernever-before-seen thread, on every refresh cycle, whenever "Hide userland
process threads" (
hide_userland_threads=1in htoprc) is enabled.When
tidhas never been seen before,ProcessTable_getProcess()constructs a fresh object (
xCalloc) but does not add it to the table --that only happens at the bottom of the loop body, past the
continue. Theobject is then:
same
tidallocates yet another new object), andTable_cleanupEntries()(so it's never freed viaProcess_delete/Process_done).linux/LinuxProcessTable.chas the equivalent hide-branch but guards itwith
preExisting &&, specifically so a thread is always registered onfirst sight before being hidden on later scans:
Darwin's version is missing that guard.
Fix
Minimal change, keeps the existing short-circuit structure -- just
registers the object before continuing:
Impact / how this was found
On a host with heavy, sustained thread churn (a multi-agent workload host,
~3000 live system threads), this leaks continuously. Found via
vmmapdiagnosis of a separate, unexplained ~2GB physical-footprint / ~3.3M-live-
allocation growth on a long-running htop instance -- that instance had
hide_userland_threads=0, so this bug wasn't the cause of that specificgrowth, but is a real, independent leak, confirmed by code review and
reproduced by inspection of the code path (this fix has been soak-tested
locally via a MacPorts overlay build pinned to this branch).
Full write-up: eejd#2
Opening as draft while the local soak test runs longer to build confidence
before requesting review.
Assisted-by: Claude Sonnet 5 noreply@anthropic.com