Skip to content

fix(windows): isolate detached launch stdio handles - #38

Merged
alkoleft merged 8 commits into
alkoleft:masterfrom
korolevpavel:fix/windows-detached-stdio
Aug 3, 2026
Merged

fix(windows): isolate detached launch stdio handles#38
alkoleft merged 8 commits into
alkoleft:masterfrom
korolevpavel:fix/windows-detached-stdio

Conversation

@korolevpavel

@korolevpavel korolevpavel commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Closes #31.

What changed

  • clears HANDLE_FLAG_INHERIT from the runner's Windows stdin/stdout/stderr handles before detached and managed-detached process creation
  • keeps the runner's own standard I/O open and usable while preventing the 1C process tree from extending caller pipe lifetime
  • preserves Rust's explicit NUL child streams and existing Job Object behavior
  • treats null, sentinel, and stale ERROR_INVALID_HANDLE standard handles as absent; other Win32 failures remain fail-closed through ProcessError::SpawnFailed
  • adds a Windows subprocess regression that requires redirected stdout EOF while the detached child PID is still alive
  • bounds test cleanup and surfaces taskkill failures

Why this boundary

Stable Rust does not expose the Win32 process attribute handle allowlist. A custom CreateProcessW path would duplicate Rust command-line, environment, working-directory, child ownership, and Job Object semantics. Permanently clearing only the inherit flag is idempotent, does not close the handles, and avoids a temporary clear/restore race.

Verification

  • focused process suite: 11 passed
  • launch unit suite: 6 passed
  • MCP launch service suite: 8 passed
  • cargo fmt --all -- --check, cargo check --all-targets, clippy, and git diff --check passed
  • known startup-probe and two CLI timing failures reproduce on base be558db
  • independent tester, whole-branch reviewer, and mandatory Rust expert reviews are clean

Platform note

The local Homebrew Rust toolchain has no Windows target, so the cfg-gated EOF/liveness regression requires Windows CI/runtime confirmation. The windows-sys signatures, features, handle sentinels, and error semantics were checked against the local generated bindings and Microsoft Win32 documentation.

Summary by CodeRabbit

  • Исправления

    • Исправлено удержание перенаправленного стандартного вывода после завершения detached-процессов на Windows.
    • Потоки stdin, stdout и stderr теперь корректно изолируются для detached-режимов без изменения поведения захваченного ввода-вывода.
    • Улучшена обработка некорректных дескрипторов и завершения дочерних процессов.
  • Документация

    • Добавлены план и описание дизайна изоляции стандартных дескрипторов Windows.
  • Тестирование

    • Добавлены регрессионные проверки своевременного завершения перенаправленного вывода в detached-режимах.

- document the inherited-handle root cause and stable boundary
- plan TDD, Windows regression coverage, and independent review
- clear inheritance from valid runner standard handles before detached spawns
- cover process-mode policy and redirected stdout EOF behavior
- promote task headings and remove trailing blank lines
- clear inheritance without a query race and ignore ERROR_INVALID_HANDLE
- bound EOF regression cleanup and expose taskkill failures
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

В Windows добавлена изоляция наследуемых стандартных handle перед запуском Detached и ManagedDetached. Обновлены документация, зависимость windows-sys, процессные тесты и Windows contract scope.

Changes

Изоляция detached stdio в Windows

Layer / File(s) Summary
Контракт режимов и Windows API
Cargo.toml, docs/superpowers/..., src/platform/process.rs
Добавлена зависимость windows-sys. Описаны правила изоляции. Определено применение изоляции для Detached и ManagedDetached, но не для Captured.
Изоляция handle перед spawn
src/platform/process.rs
Перед spawn очищается HANDLE_FLAG_INHERIT у стандартных handle. Некорректные handle и ERROR_INVALID_HANDLE пропускаются. Остальные ошибки преобразуются в ProcessError::SpawnFailed.
Регрессия EOF и CI-проверки
src/platform/process.rs, scripts/test/*, spec/acceptance/real-environment-validation.md
Windows-тесты проверяют EOF при живом detached-процессе, классификацию режимов и результаты cleanup. Contract scope проверяет наличие и запускает два целевых теста.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant WindowsTest
  participant V8Runner
  participant WindowsAPI
  participant DetachedChild
  participant StdoutReader
  WindowsTest->>V8Runner: Запуск Detached или ManagedDetached
  V8Runner->>WindowsAPI: Очистка HANDLE_FLAG_INHERIT
  WindowsAPI-->>V8Runner: Результат изоляции
  V8Runner->>DetachedChild: Spawn
  V8Runner-->>WindowsTest: Возврат PID
  StdoutReader->>V8Runner: Чтение stdout pipe
  V8Runner-->>StdoutReader: EOF до завершения DetachedChild
Loading

Possibly related PRs

  • alkoleft/v8-runner-rust#13: изменяет src/platform/process.rs и связан с управлением процессами Windows.
  • alkoleft/v8-runner-rust#34: связан с поведением Detached и ManagedDetached при запуске процессов.

Suggested reviewers: alkoleft

Poem

Я, кролик, handle снимаю,
Pipe до EOF провожаю.
Detached бежит, PID живёт,
А reader конец потока найдёт.
Windows-тест скачет вперёд.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Заголовок точно описывает основное изменение: изоляцию stdio-дескрипторов при detached-запуске в Windows.
Linked Issues check ✅ Passed Изменения решают проблему #31: изоляция наследуемых Windows stdio handle предотвращает удержание stdout pipe, а тесты проверяют EOF при живом detached-процессе.
Out of Scope Changes check ✅ Passed Изменения в коде, зависимостях, тестах, документации и CI относятся к исправлению #31 и его проверке.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@korolevpavel

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

- preserve Windows standard-handle isolation for detached modes
- retain master managed-wait command construction

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/platform/process.rs`:
- Around line 586-624: Update isolate_inherited_standard_handles to detect real
Windows console handles before calling SetHandleInformation, using the
appropriate console-handle check. Ignore SetHandleInformation errors for console
handles, while preserving error propagation for non-console pipe/handle values
so inheritance isolation remains enforced.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7e4a9d41-4172-41bf-960e-894dac89e499

📥 Commits

Reviewing files that changed from the base of the PR and between d612e2d and 6d8d8c8.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • Cargo.toml
  • docs/superpowers/plans/2026-07-22-windows-detached-stdio-isolation.md
  • docs/superpowers/specs/2026-07-22-windows-detached-stdio-isolation-design.md
  • src/platform/process.rs

Comment thread src/platform/process.rs
korolevpavel and others added 3 commits July 26, 2026 23:07
- ignore SetHandleInformation failures only for console handles\n- keep non-console handle failures actionable\n- cover console-only failure policy
- ignore only stale ERROR_INVALID_HANDLE failures
- cover redirected stdout EOF for both detached launch modes
- run targeted regressions in Windows contract CI

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
src/platform/process.rs (1)

587-613: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Проверить обработку SetHandleInformation для реальных консольных handle-ов.

Прошлый обзор уже указывал, что SetHandleInformation может завершаться ошибкой на консольных handle-ах с кодом, отличным от ERROR_INVALID_HANDLE. В показанном коде логика не изменилась: is_invalid_standard_handle_error по-прежнему игнорирует только код 6, а обнаружение консольных handle-ов (например, через GetFileType) не добавлено. Комментарий помечен как "✅ Addressed in commit 081c943", но видимая реализация isolate_inherited_standard_handles (строки 587-613) не отражает такое исправление — изменение в строках 602-603 затрагивает только SAFETY-комментарий.

Независимое исследование подтверждает: Calling SetHandleInformation(dwMask=HANDLE_FLAG_INHERIT) fails on console handles, so the inheritability of an existing console handle cannot be changed. При этом сам подход (сбрасывать HANDLE_FLAG_INHERIT у собственных std-handle-ов раннера перед detached-запуском) — это признанный workaround: windows: when creating process with redirected stdio, make parent's std handles not inheritable.

Если runner запущен интерактивно (stdout/stderr не перенаправлены и указывают на реальную консоль), isolate_inherited_standard_handles может вернуть ошибку, отличную от ERROR_INVALID_HANDLE, и spawn_command завершится как ProcessError::SpawnFailed для Detached/ManagedDetached — то есть обычный интерактивный запуск CLI-инструмента может перестать работать.

Уточните код ошибки, который реально возвращает SetHandleInformation для консольных handle-ов на целевых версиях Windows, и при необходимости добавьте проверку типа handle-а (GetFileType) перед вызовом SetHandleInformation, пропуская ошибку для консольных handle-ов вместо только ERROR_INVALID_HANDLE.

Запустите скрипт для проверки полного тела is_invalid_standard_handle_error и наличия какой-либо консольной проверки, не попавшей в предоставленный фрагмент:

#!/bin/bash
set -euo pipefail
ast-grep outline src/platform/process.rs --items all --match 'is_invalid_standard_handle_error|isolate_inherited_standard_handles' --view expanded
rg -n -A 15 'fn is_invalid_standard_handle_error' src/platform/process.rs
rg -n 'GetFileType|GetConsoleMode|FILE_TYPE_CHAR' src/platform/process.rs

Также подтвердите ожидаемый код ошибки SetHandleInformation для консольных handle-ов на актуальных версиях Windows.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/process.rs` around lines 587 - 613, Update
isolate_inherited_standard_handles to recognize real console standard handles
before or during SetHandleInformation, using the appropriate Win32
handle-type/console detection and preserving the existing ERROR_INVALID_HANDLE
handling. Treat the known console-handle failure as ignorable so interactive
stdout/stderr do not cause the function to return an error, while still
propagating unexpected failures; verify the relevant Windows error code and
reuse or update is_invalid_standard_handle_error as appropriate.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@src/platform/process.rs`:
- Around line 587-613: Update isolate_inherited_standard_handles to recognize
real console standard handles before or during SetHandleInformation, using the
appropriate Win32 handle-type/console detection and preserving the existing
ERROR_INVALID_HANDLE handling. Treat the known console-handle failure as
ignorable so interactive stdout/stderr do not cause the function to return an
error, while still propagating unexpected failures; verify the relevant Windows
error code and reuse or update is_invalid_standard_handle_error as appropriate.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 64446541-ad5f-4f46-a61e-869b32f678aa

📥 Commits

Reviewing files that changed from the base of the PR and between 6d8d8c8 and dd5f7f2.

📒 Files selected for processing (4)
  • scripts/test/README.md
  • scripts/test/ci-rust.sh
  • spec/acceptance/real-environment-validation.md
  • src/platform/process.rs

@alkoleft
alkoleft merged commit 7ce1b06 into alkoleft:master Aug 3, 2026
5 checks passed
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.

bug(windows): detached launch keeps caller stdout pipe open until 1cv8c exits

2 participants