fix: prevent Process.HasExited race causing UnobservedTaskException#362
Closed
fix: prevent Process.HasExited race causing UnobservedTaskException#362
Conversation
The crash log shows InvalidOperationException ('No process is associated
with this object') when Process.HasExited is accessed on a disposed process.
Fire-and-forget tasks monitoring stdout/stderr in DevTunnelService accessed
the _hostProcess field directly, which could be nulled/disposed by Stop()
or TryHostTunnelAsync() concurrently. The same pattern existed in
CodespaceService.TunnelHandle and ServerManager.StopServer.
Changes:
- Add ProcessHelper utility with SafeHasExited(), SafeKill(), and
SafeKillAndDispose() that never throw on disposed/invalid processes
- DevTunnelService: capture process in local variable before passing to
fire-and-forget tasks; use ProcessHelper.SafeHasExited() in loops
- CodespaceService.TunnelHandle: add _disposed flag so IsAlive returns
false after DisposeAsync(); use SafeHasExited for process checks
- ServerManager.StopServer: use SafeKillAndDispose for clean teardown
- Add 11 unit tests covering null, disposed, exited, and running process
states plus a concurrent-dispose regression test
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Owner
Author
|
Closing — pushing to PR #322 branch instead |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The crash log shows \InvalidOperationException: No process is associated with this object\ from \Process.HasExited\ accessed on a disposed process. This surfaced as an \UnobservedTaskException\ in the SDK's \CopilotClient.StartCliServerAsync\ process monitor, and the same unsafe pattern existed in PolyPilot's own code.
Root Cause
Fire-and-forget tasks in \DevTunnelService.TryHostTunnelAsync()\ accessed the _hostProcess\ field directly in their loop conditions (\while (!_hostProcess.HasExited)). When \Stop()\ or a subsequent \TryHostTunnelAsync()\ call disposed/nulled the field concurrently, the background tasks threw \InvalidOperationException.
The same pattern existed in:
Fix
Tests
11 new unit tests in \ProcessHelperTests.cs: