Fix Windows autospawned daemon inheriting stray handles #119

Open
opened 2026-09-05 00:20:09 +09:00 by natsukium · 0 comments
Owner

Migrated from docs/backlog.md (Blocked / Windows: the autospawned daemon inherits stray handles).

Blocked on rust-lang/rust#146407 (CommandExt::inherit_handles, unstable). CreateProcessW copies every inheritable handle of the parent into the child, and Rust's Command calls it that way whenever stdio is set, so the daemon spawn_daemon_child starts carries a copy of whatever the client inherited from its parent, and the daemon outlives the client by design. A caller that captures the client's output through a pipe ($(felis sessions …) in PowerShell, a CI step's log pipe) therefore sees no EOF until the daemon exits. On Unix nothing leaks: every fd Rust opens is CLOEXEC and stdio is replaced by /dev/null. The Windows smoke works around it by killing the daemon inside the step (windows.yml windows-smoke); a fix in the client needs either the unstable extension above or a direct CreateProcessW with PROC_THREAD_ATTRIBUTE_HANDLE_LIST, an unsafe site that would need its own audited relaxation. Revisit when inherit_handles stabilizes, or if a user hits the hang outside CI.

Fix options: wait for inherit_handles stabilization, or call CreateProcessW with PROC_THREAD_ATTRIBUTE_HANDLE_LIST (audited unsafe).

Revisit when the API stabilizes or a user reports a hang outside CI (e.g. PowerShell $(felis sessions …) or CI log pipe).

Refs: crates/felis-client-core spawn_daemon_child, .forgejo/workflows/windows.yml.

Migrated from `docs/backlog.md` (Blocked / Windows: the autospawned daemon inherits stray handles). > Blocked on rust-lang/rust#146407 (`CommandExt::inherit_handles`, unstable). `CreateProcessW` copies every inheritable handle of the parent into the child, and Rust's `Command` calls it that way whenever stdio is set, so the daemon `spawn_daemon_child` starts carries a copy of whatever the client inherited from *its* parent, and the daemon outlives the client by design. A caller that captures the client's output through a pipe (`$(felis sessions …)` in PowerShell, a CI step's log pipe) therefore sees no EOF until the daemon exits. On Unix nothing leaks: every fd Rust opens is `CLOEXEC` and stdio is replaced by `/dev/null`. The Windows smoke works around it by killing the daemon inside the step (`windows.yml` `windows-smoke`); a fix in the client needs either the unstable extension above or a direct `CreateProcessW` with `PROC_THREAD_ATTRIBUTE_HANDLE_LIST`, an `unsafe` site that would need its own audited relaxation. Revisit when `inherit_handles` stabilizes, or if a user hits the hang outside CI. Fix options: wait for `inherit_handles` stabilization, or call `CreateProcessW` with `PROC_THREAD_ATTRIBUTE_HANDLE_LIST` (audited `unsafe`). Revisit when the API stabilizes or a user reports a hang outside CI (e.g. PowerShell `$(felis sessions …)` or CI log pipe). Refs: `crates/felis-client-core` `spawn_daemon_child`, `.forgejo/workflows/windows.yml`.
Sign in to join this conversation.
No description provided.