Repository navigation
Description
Problem
get_serve_info() decides whether the serve lock (.iroh-serve.lock, pkgs/id/src/lib.rs:311) is stale by calling is_process_alive(info.pid), where pid comes straight from the lock file's JSON (ServeInfo.pid: u32, pkgs/id/src/commands/serve.rs:130-141). is_process_alive (serve.rs:196-210) casts that u32 to i32 and calls libc::kill(pid as i32, 0), with a comment claiming the cast is safe because "valid PIDs on Unix are always positive and fit in i32". That holds for a pid written by create_serve_lock (std::process::id()), but not for the pid read back from disk: serde accepts any u32, and two values make the stale check answer "alive" for no process at all:
pid: 0→kill(0, 0)checks the caller's own process group — it succeeds whenever the calling process exists, i.e. always.pid: 4294967295(u32::MAX) → casts to-1→kill(-1, 0)succeeds if any process the caller may signal exists, i.e. always.
A lock file carrying either value is therefore never treated as stale: get_serve_info returns the bogus ServeInfo and never deletes the lock (serve.rs:171-185). Every command that consults the lock first — get, put, list, peers, the REPL and the meta client (commands/get.rs:101, put.rs:153, list.rs:72, peers.rs:204, repl.rs:235, meta_client.rs:103) — then tries to reach a serve instance that does not exist instead of falling back to a local node / "no serve running".
Reachability is mundane, not adversarial: a hand-edited, corrupted-but-still-JSON-parseable, or partially migrated lock file (or any future writer that records a sentinel pid) permanently wedges serve discovery for that directory until a human deletes .iroh-serve.lock by hand.
Evidence (verified this run, main 8124cc0b)
Probe on the laptop (~/git/fleet/probe-2026-10-29-pidalive/), running is_process_alive copied verbatim from serve.rs:196-210:
own pid 3726549 -> true
pid 0 -> true
pid u32::MAX (4294967295, casts to -1) -> true
pid 4294967294 (casts to -2) -> false
dead pid 3727865 -> false (spawned, reaped, then checked)
pid 999999 (likely dead) -> false
So ordinary dead pids are correctly reported dead; only the sentinel/wrapped values lie. Dedup: gh searches for is_process_alive, serve lock, and pid reuse returned no issue covering this (only closed #443, about gitignoring serve artifacts).
Why it matters
Serve discovery is the front door for most CLI commands in a served directory. A lock that can never go stale turns a recoverable state (dead serve) into a permanent, confusing failure (connection attempts to a dead/wrong endpoint), with the fix — deleting a dotfile — undiscoverable from any error message.
Acceptance criteria
-
is_process_alive(orget_serve_info) refuses non-positive / out-of-range pids:pid == 0and any pid that does not fit a positivei32are treated as "not alive" (stale lock), never passed tokill. - A lock file with
pid: 0orpid: 4294967295is removed byget_serve_infoandNoneis returned, exactly as for an ordinary dead pid. - A live pid and an ordinary dead pid behave exactly as before.
- Regression tests cover pid 0,
u32::MAX, a dead pid, and the caller's own pid. - The misleading cast-safety comment is corrected to state where the pid is validated.
Activity
developing-today commentedon Oct 29, 2026
CODE-1039
dezren39 commentedon Oct 29, 2026
🤖 Agent note · filed
130 remaining items
dezren39 commentedon Nov 2, 2026
agent-note:v1
dezren39 commentedon Nov 2, 2026
🤖 Agent note · picked up (resumed)
dezren39 commentedon Nov 2, 2026
🤖 Agent note · parked
dezren39 commentedon Nov 2, 2026
agent-note:v1
kind: pickup
task: 5185
lane: c
state: claimed
note: Lane C picked up task 5185. Ownership correction on the record: the earlier Drew-owned park used the author+assignee=dezren39 heuristic. Fresh check 2026-11-02T12:17Z shows PR #4097 is on fleet branch queue/5185-2142-pid-guard (this task's own branch), and neither issue #2142 nor PR #4097 carries any hard-stop label (held, user/owned, do-not-merge, do-not-auto-edit). PR #4097 is the canonical task-bound PR; resuming from it: diff review, Codex findings, CI, merge when verified.
dezren39 commentedon Nov 2, 2026
agent-note:v1
kind: done
task: 5185
lane: c
state: done (fixed_merged)
note: PR #4097 merged as 3d6deea; issue auto-closed. Verification: diff matches triage task 3146's pinned fix exactly (guard inside is_process_alive, corrected cast comment, regression tests); Codex review on head 0002eb3 reported no findings; laptop cargo test is_process_alive: 5 passed including the new pid 0 and out-of-i32-range tests. PR CI was red for unrelated reasons: Magic Nix Cache rate-limit throttling (HTTP 418) in test-unit and pre-existing rustfmt drift in files this PR does not touch (retention_pruning.rs, cli_integration.rs).