Skip to content

Fix 4 critical correctness bugs in daemon server#3

Merged
schovi merged 1 commit intomainfrom
fix/phase1-critical-correctness
Feb 18, 2026
Merged

Fix 4 critical correctness bugs in daemon server#3
schovi merged 1 commit intomainfrom
fix/phase1-critical-correctness

Conversation

@schovi
Copy link
Owner

@schovi schovi commented Feb 17, 2026

Bug

The daemon server has four correctness bugs that can cause crashes, hangs, or undefined behavior under normal operation. Negative search context values panic the daemon (DoS vector for any client including MCP agents). The kill handler blocks the entire daemon under mutex while waiting for process death. Multiple code paths can double-close PTY file descriptors. A data race exists on s.listener between Start() and Shutdown().

Solution

All four issues are fixed with minimal, targeted changes. Input validation rejects negative before/after values at three boundaries (server, CLI, MCP). The kill handler releases the mutex before async process cleanup, mirroring the existing handleStop pattern. A ptyHandle wrapper with sync.Once guarantees each PTY fd is closed exactly once regardless of which code path runs first. The listener nil-check in Start() now runs under the mutex to match Shutdown().

Changes

Search validation (server.go, cmd/search.go, internal/mcp/tools.go):

  • Server rejects before < 0 || after < 0 before touching any state
  • CLI validates after --around expansion
  • MCP validates after around expansion

Kill handler (server.go):

  • handleKill captures process reference under lock, releases lock, then spawns goroutine for SIGTERM/SIGKILL/Wait

PTY double-close (server.go):

  • New ptyHandle type wraps *os.File with sync.Once close
  • s.ptys map stores *ptyHandle instead of *os.File
  • All PTY consumers (captureOutput, handleStop, handleKill, Shutdown, handleSnapshot, handleSend, handleResize) use the handle

Listener race (server.go):

  • s.listener == nil check in Start() accept loop now holds s.mu

Phase 1 release blockers: negative search context crash (DoS via
makeslice panic), handleKill blocking the entire daemon under mutex,
PTY double-close race between captureOutput and stop/kill/shutdown,
and data race on s.listener between Start and Shutdown.

- Validate before/after non-negative at server, CLI, and MCP boundaries
- Make handleKill async (mirror handleStop pattern, release lock before process cleanup)
- Introduce ptyHandle with sync.Once to guarantee single PTY close
- Guard s.listener nil check in Start() with mutex
@schovi schovi marked this pull request as ready for review February 18, 2026 02:57
@schovi schovi merged commit 9460c76 into main Feb 18, 2026
6 checks passed
@schovi schovi deleted the fix/phase1-critical-correctness branch February 18, 2026 03:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant