Refactor Process.StartCore to accept SafeFileHandle parameters for stdin/stdout/stderr#125766
Refactor Process.StartCore to accept SafeFileHandle parameters for stdin/stdout/stderr#125766
Conversation
…ation and stream setup to Process.cs Co-authored-by: adamsitnik <[email protected]>
…nterop.Pipe.cs to csproj Co-authored-by: adamsitnik <[email protected]>
|
Tagging subscribers to this area: @dotnet/area-system-diagnostics-process |
adamsitnik
left a comment
There was a problem hiding this comment.
@copilot address my feedback
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj
Outdated
Show resolved
Hide resolved
…eAnonymousPipe directly, simplify Windows StartWithCreateProcess Co-authored-by: adamsitnik <[email protected]>
All feedback addressed in commit 07d9369:
|
|
@copilot please update the PR description based on my commits and then invoke the code-review skill and post your analysis/results as a comment on this PR |
PR description updated. Code review follows below. 🤖 Copilot Code ReviewHolistic AssessmentMotivation: This refactoring lifts pipe creation out of platform-specific code into the shared Approach: The approach is sound — pipes are created uniformly via Summary: ✅ LGTM. The refactoring is correct, handles resource management properly, and the locking scheme is well-designed. Two models (Gemini 2.5 Pro and Claude Opus 4.5) reviewed this independently; their findings converge. No blocking issues found. Detailed Findings✅ Resource management — Console handles are safe to disposeThe
Disposing a non-owning ✅ Handle ownership transfer in Unix OpenStream — No double-disposeThe Unix SafePipeHandle safePipeHandle = new(handle.DangerousGetHandle(), ownsHandle: true);
handle.SetHandleAsInvalid();
handle.Dispose();The parent pipe handles ( ✅ Platform-conditional handle creation — Assertions are correctThe condition
✅ Native dup2 now unconditional — SafeThe native code now always calls ✅ Locking scheme — Correctly prevents handle inheritance leaks
The lock is shared across platforms via 💡 Minor — Comment could be more preciseThe comment at line 1372 ("We MUST close the parent copies of the child handles") is slightly misleading for the non-redirect case where handles came from Models contributing to this review: Claude Sonnet 4 (primary), Gemini 2.5 Pro, Claude Opus 4.5 |
- STARTF_USESTDHANDLES is always provided now - we may use more flags in the future - so ProcessWindowStyle tests should check only if STARTF_USESHOWWINDOW (1) was applied
I am not sure this API shape is going to fly well - it is inconsistent with what's there today. I think the SafeFileHandles should be members on ProcessStartInfo and be mutually exclusive with the other ways to redirect input/output. |
… 0/1/2; remove Android checks from Process.cs Co-authored-by: adamsitnik <[email protected]>
|
We should start from the use-cases/issues, propose the API and design (which may involve some prototyping/derisking) and then the actual implementation follows. You may have a picture about the API and design. I don't think it is written down so others can understand what way we're heading and how it solves the user issues. I can technically review if this refactoring isn't breaking anything, but currently I can't say why we need it, which is the more important thing. Personally, I prefer we capture such information in an issue. PRs are already implementation centric and the coding agent workflows make it even more focused on code and code changes. |
…rning fd 0/1/2; remove Android checks from Process.cs" This reverts commit bba0144.
adamsitnik
left a comment
There was a problem hiding this comment.
@copilot please address my feedback
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Unix/System.Native/Interop.ForkAndExecProcess.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Unix/System.Native/Interop.ForkAndExecProcess.cs
Outdated
Show resolved
Hide resolved
…ndle nullable handles Co-authored-by: adamsitnik <[email protected]> Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/264e5c0b-daf2-4f32-80ec-10fdf888c120
…eam (possibly a terminal) Co-authored-by: adamsitnik <[email protected]> Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/264e5c0b-daf2-4f32-80ec-10fdf888c120
Addressed in 6718589 and 6ddf417:
|
@tmds @jkotas I am all aware of that. I must admit that the fact that Since we all agreed that exposing the ability to redirect standard handles to any file handle is good idea and the API design review meetings happen once per week, I was hoping to reduce the time it will take to get the approved API merged by preparing the repo with necessary refactor first. My entire idea was following:
So I wanted to optimize the performance and deliver the new API slightly faster. I apologize for not being clear and wasting your time. |

Description
Refactors
StartCoreon both Windows and Unix to accept nullableSafeFileHandleinstances for child process standard streams, enabling future scenarios where callers provide pre-existing handles. Pipe creation and stream setup are lifted into the sharedProcess.cs:Start()method, with platform-specificOpenStreamand encoding helper methods defined directly in each platform file (no partial methods). Handles are only created for redirected streams — non-redirected streams passnulltoStartCore, allowing the child process to inherit the parent's standard handles.Native layer (
pal_process.c,pal_process.h,pal_process_wasi.c)stdinFd/stdoutFd/stderrFdchanged fromint32_t*(out) toint32_t(in) — caller now owns pipe creationSystemNative_Pipecalls) and associatedProcessCreateLockdup2of the provided fds ontoSTDIN_FILENO/STDOUT_FILENO/STDERR_FILENOis conditional — skipped when fd is-1(meaning the stream is not redirected and the child inherits the parent's handle)redirectStdin/redirectStdout/redirectStderrparameters from native signatureNew native entry point (
pal_io.c,pal_io.h)SystemNative_IsAtomicNonInheritablePipeCreationSupported— returns 1 whenHAVE_PIPE2is defined, 0 otherwise; used by managed code to decide whether pipe creation requires a write lockInterop layer (
Interop.ForkAndExecProcess.cs)out int stdinFd/stdoutFd/stderrFdtoint stdinFd/stdoutFd/stderrFd(in parameters)SafeFileHandle?parameters and usesDangerousGetHandle/DangerousAddRef/DangerousReleaseto safely extract raw handles, passing-1for null handlesredirectStdin/redirectStdout/redirectStderrboolean parametersNew interop declarations
Interop.IsATty.cs: AddedSafeFileHandleoverload ofIsATtyInterop.IsAtomicNonInheritablePipeCreationSupported.cs: New P/Invoke withNullableBoolcaching forSystemNative_IsAtomicNonInheritablePipeCreationSupportedManaged layer
Process.cs:Start()now creates pipes viaSafeFileHandle.CreateAnonymousPipeonly for redirected streams. On platforms withoutpipe2, aWriteLockwraps pipe creation to prevent accidental handle inheritance. AfterStartCore, sets up_standardInput/_standardOutput/_standardErrorstreams via platform-specificOpenStream. TheCantRedirectStreamsvalidation forUseShellExecuteis moved here from platform files.Process.Unix.cs:StartCoretakesSafeFileHandle?parameters (null for non-redirected streams). Terminal detection (usesTerminal) treats null handles as potentially pointing to a terminal (since the child inherits the parent's stream).OpenStreamtransfers ownership fromSafeFileHandletoSafePipeHandleand wraps inAnonymousPipeClientStream.GetStandardInputEncoding/GetStandardOutputEncodingreturnEncoding.Default.s_processStartLockmoved to sharedProcessUtils.Process.Windows.cs:StartWithCreateProcesstakes nullableSafeFileHandle?parameters. When any handle is non-null, handles are duplicated as inheritable viaDuplicateAsInheritableandSTARTF_USESTDHANDLESis set. The oldCreatePipehelper ands_createProcessLockare removed. The lock is replaced byProcessUtils.s_processStartLock.EnterWriteLock().OpenStreamwraps handle inFileStream.GetStandardInputEncoding/GetStandardOutputEncodinguse console code pages.Process.Win32.cs:StartCoresignature updated; asserts thatUseShellExecuteimplies all-null handles.CantRedirectStreamscheck removed (moved to sharedProcess.cs).ProcessUtils.cs: Now hostss_processStartLock(shared across platforms).Process.ConfigureTerminalForChildProcesses.Unix.cs: ReferencesProcessUtils.s_processStartLockinstead of the removed instance field.Console changes (Android support — reverted)
ConsolePalchanges to return fd 0/1/2 were reverted per reviewer feedback.Console.OpenStandard*Handlemethods continue to throwPlatformNotSupportedExceptionon Android. The Process refactoring avoids calling these APIs for non-redirected streams by passing null handles instead.Build verification
TestGetProcesses)🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.