fix(codegraph): stop leaking detached MCP daemons and indexing the whole drive (#3747)#3755
Merged
Merged
Conversation
added 2 commits
June 9, 2026 19:31
… MCP children are reaped A Windows stdio MCP launcher (cmd.exe -> node.exe, as the CodeGraph daemon re-parents itself off its shim) raced the job-object assignment: the job was assigned only after Start returned, so a fast shim could exec its grandchild and exit before the assignment, leaving node.exe orphaned in no job. KillTracked and an abrupt reasonix exit then both missed it, and dozens of codegraph daemons leaked past a session (#3747). Create the child suspended, assign it to the job, then resume — so every descendant is captured before the launcher can spawn anything.
When the workspace root resolved to a drive root (C:\), CodeGraph's cwd-aware serve --mcp walked the entire volume — C:\Windows, Program Files, everything — pinning ~1GB of RAM (#3747). Reject filesystem roots (and an empty root) at both spawn sites before launching serve.
This was referenced Jun 10, 2026
SuMuxi66
pushed a commit
to SuMuxi66/DeepSeek-Reasonix
that referenced
this pull request
Jun 10, 2026
…ole drive (esengine#3747) (esengine#3755) * fix(proc): assign the job object before the launcher runs so detached MCP children are reaped A Windows stdio MCP launcher (cmd.exe -> node.exe, as the CodeGraph daemon re-parents itself off its shim) raced the job-object assignment: the job was assigned only after Start returned, so a fast shim could exec its grandchild and exit before the assignment, leaving node.exe orphaned in no job. KillTracked and an abrupt reasonix exit then both missed it, and dozens of codegraph daemons leaked past a session (esengine#3747). Create the child suspended, assign it to the job, then resume — so every descendant is captured before the launcher can spawn anything. * fix(codegraph): refuse to index a filesystem root When the workspace root resolved to a drive root (C:\), CodeGraph's cwd-aware serve --mcp walked the entire volume — C:\Windows, Program Files, everything — pinning ~1GB of RAM (esengine#3747). Reject filesystem roots (and an empty root) at both spawn sites before launching serve. --------- Co-authored-by: reasonix <reasonix@deepseek.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
#3747: after a session, dozens of orphaned
codegraph serve --mcpnode processes survived (~1.7 GB), and one instance launched with cwdC:\indexed the entire system drive (~1 GB).Two independent Reasonix-side root causes.
1. The job object lost the race against the launcher
Each stdio MCP server starts as
cmd.exe -> node.exe; CodeGraph's shim re-parents the node daemon off the launcher.TrackTreeassigned the process to its kill-on-close Job Object aftercmd.Start()returned — but a fast.cmdshim can exec node and exit before that assignment lands, leavingnode.exeorphaned in no job.KillTracked(and an abrupt reasonix exit, which relies on the job handle closing) then can't reap it, so every failed/closed handshake leaks a daemon.Fix:
proc.StartTrackedcreates the child suspended, assigns it to the job while it is still frozen, then resumes it — so the launcher and every descendant it spawns are captured before any code runs. The process is always resumed (even if assignment fails) so a child can never be left wedged suspended.2. A filesystem-root cwd indexed the whole volume
CodeGraph is cwd-aware; when the project root resolved to
C:\it walked the entire drive.codegraph.IndexableRootnow rejects drive roots, UNC share roots,/, and an empty root — checked at both spawn sites (boot and the/codegraphconnect path) before launchingserve.Tests
proc: job assignment + reap throughStartTracked; a deterministic resume check (a suspended child that must run to exit 7, so a missed resume fails instead of hanging).codegraph:IndexableRootrejectsC:\,\server\share,/, and"".Verified locally on Windows 11:
golangci-lintclean,go vet, and the proc / codegraph / plugin / boot / control package tests pass.Not in this PR
Dedup of concurrent codegraph spawns and an idle-timeout watchdog (#3747 items 2-3) are follow-ups. With reaping now reliable, leaked handles are felled on close and on exit, which removes the surviving-orphan harm; dedup/idle-timeout are an optimization on top.
Closes #3747