From 57f062a9b674426756ea92d1ed119a406144ab95 Mon Sep 17 00:00:00 2001 From: groblegark Date: Sun, 25 Jan 2026 18:01:52 -0800 Subject: [PATCH] fix(tmux): add -- to kill commands to prevent procps-ng argument parsing bug (#928) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The procps-ng kill binary (version 4.0.4+) has an argument parsing issue where negative PIDs like "-12345" are misinterpreted as options because they start with a dash. This causes the binary to fall back to "-1" which means "all processes", resulting in kill(-1, signal) being called. This was discovered through an extensive murder investigation after 26 Claude AI instances were killed when running TestCleanupOrphanedSessions. Each investigator left notes for their successor, eventually leading to the discovery that: - exec.Command("bash", "-c", "kill -KILL -PGID") is SAFE (uses bash builtin) - exec.Command("kill", "-KILL", "-PGID") is FATAL (uses /usr/bin/kill) Verified via strace: /usr/bin/kill -KILL -12345 → kill(-1, SIGKILL) # WRONG! /usr/bin/kill -KILL -- -12345 → kill(-12345, SIGKILL) # Correct! The fix adds "--" before negative PGID arguments to explicitly end option parsing, ensuring the negative number is treated as a PID/PGID argument. Full investigation: https://github.com/groblegark/gastown/blob/main/MURDER_INVESTIGATION.md Co-authored-by: Refinery Co-authored-by: Claude Opus 4.5 --- internal/tmux/tmux.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/internal/tmux/tmux.go b/internal/tmux/tmux.go index a8a521d3..45c7c1a2 100644 --- a/internal/tmux/tmux.go +++ b/internal/tmux/tmux.go @@ -187,10 +187,13 @@ func (t *Tmux) KillSessionWithProcesses(name string) error { if pgid != "" && pgid != "0" && pgid != "1" { // Kill process group with negative PGID (POSIX convention) // Use SIGTERM first for graceful shutdown - _ = exec.Command("kill", "-TERM", "-"+pgid).Run() + // NOTE: The "--" is CRITICAL! Without it, procps-ng kill (v4.0.4+) + // misparses "-PGID" as an option and ends up calling kill(-1) which + // kills ALL processes! See https://github.com/groblegark/gastown/blob/main/MURDER_INVESTIGATION.md + _ = exec.Command("kill", "-TERM", "--", "-"+pgid).Run() time.Sleep(100 * time.Millisecond) // Force kill any remaining processes in the group - _ = exec.Command("kill", "-KILL", "-"+pgid).Run() + _ = exec.Command("kill", "-KILL", "--", "-"+pgid).Run() } // Also walk the process tree for any descendants that might have called setsid() @@ -388,9 +391,10 @@ func (t *Tmux) KillPaneProcesses(pane string) error { pgid := getProcessGroupID(pid) if pgid != "" && pgid != "0" && pgid != "1" { // Kill process group with negative PGID (POSIX convention) - _ = exec.Command("kill", "-TERM", "-"+pgid).Run() + // NOTE: The "--" is CRITICAL! See comment in KillSessionWithProcesses. + _ = exec.Command("kill", "-TERM", "--", "-"+pgid).Run() time.Sleep(100 * time.Millisecond) - _ = exec.Command("kill", "-KILL", "-"+pgid).Run() + _ = exec.Command("kill", "-KILL", "--", "-"+pgid).Run() } // Also walk the process tree for any descendants that might have called setsid()