fix(next): ProcessBox never reads the pid of a process that has not launched; a child that never reads stdin no longer crashes PhoneProcess
Merged
TE
7d ago+112+112+012345678901234567890123456789-7-7-0123456789
Two process-lifecycle crashes in the app.
Problems
ProcessBox.kill()(ProcessRunner) readprocess.processIdentifierbefore checkingisRunning.processIdentifierof aProcessthat has not launched raises, andrunhas no cancellation check: a caller that is already cancelled getsonCancel(which callskill()) before the child task has launched anything. Callers include the daemon launcher, login-environment capture, cloud credential login and the server reach/ensure paths. Every other kill site in the app (FixChild,CloudCodexBrokerSession.forceStop,HostCLI.stop) already checksisRunningfirst.PhoneProcesswrote the child's stdin withFileHandle.write(_:). A child that exits without reading (a simulator that is not booted makessimctl pbcopydo this) closes the read end, the write fails with EPIPE, andwrite(_:)raises it as an uncatchable Objective-C exception (SIGPIPE ends a process that does not ignore it). A paste larger than a pipe buffer makes the window certain.
Fix
kill()checksisRunningbefore it reads the pid;runstarts withTask.checkCancellation(), so a cancelled caller launches no child.PhoneProcesssetsF_SETNOSIGPIPEon the stdin pipe and writes withwrite(contentsOf:)(the failure is ignored: the child's exit status says what went wrong).
Tests
First commit is the tests alone, second the fixes.
ProcessRunnerCancellationTests: kill on aProcessthat never launched sends nothing; an already-cancelledProcessRunner.runthrowsCancellationErrorand never starts the child.PhoneProcessBrokenStdinTests: a 4 MB stdin totrueends the run with status 0 instead of crashing.
No capture: no visible change; process launch/cancel and stdin handling.
Agent session: agent session