Add Process.Start callback overload with ref struct ProcessStartArguments#128862
Add Process.Start callback overload with ref struct ProcessStartArguments#128862Copilot wants to merge 21 commits into
Conversation
Introduces a new Process.Start(ProcessStartInfo, Func<ProcessStartArguments, SafeProcessHandle>) overload that allows users to create processes using their own system calls while leveraging .NET's Process infrastructure (pipe management, async I/O, WaitForExit). - Added ProcessStartArguments class with platform-specific pointer properties - Added Windows implementation using BuildCommandLine/GetEnvironmentVariablesBlock - Added Unix implementation using ResolvePath/ParseArgv/AllocArgvArray/AllocEnvpArray - Updated ref assembly with new public API surface - Added Windows test using CreateProcess inside the callback - Added Unix test using posix_spawn inside the callback Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
|
Tagging subscribers to this area: @dotnet/area-system-diagnostics-process |
- reduce code duplication - acquire the locks! - fix Windows tests: enable inheritance - fix Unix implementation: handle "usesTerminal"
638b886 to
3163021
Compare
There was a problem hiding this comment.
Pull request overview
This PR adds a new public Process.Start overload that prepares stdio handles + argument/environment buffers and then delegates the actual OS process creation to a user callback, returning a Process wired up to existing Process infrastructure (streams, WaitForExit, etc.).
Changes:
- Adds new public API surface:
Process.Start(ProcessStartInfo, Func<ProcessStartArguments, SafeProcessHandle>)andProcessStartArguments. - Extends Windows/Unix start paths and
SafeProcessHandleto support invoking a callback-based start flow. - Adds Windows + Unix tests exercising callback-based process creation and output redirection.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| src/libraries/System.Diagnostics.Process/tests/ProcessHandlesTests.Windows.cs | Adds a Windows test using CreateProcess inside the callback to validate stdout redirection. |
| src/libraries/System.Diagnostics.Process/tests/ProcessHandlesTests.Unix.cs | Adds a Unix test using posix_spawn inside the callback to validate stdout redirection. |
| src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartArguments.cs | Introduces the new argument carrier type passed to the callback. |
| src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs | Threads optional callback through the Windows StartCore flow. |
| src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs | Threads optional callback through the Unix StartCore flow and updates wait-state ownership logic. |
| src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs | Adds the new public Process.Start callback overload and refactors internal start flow. |
| src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj | Adds the new ProcessStartArguments.cs to compilation. |
| src/libraries/System.Diagnostics.Process/src/Resources/Strings.resx | Adds a resource string for invalid callback handle errors. |
| src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Windows.cs | Adds Windows callback start helper that builds/pins command line + env block and enables handle inheritance. |
| src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Unix.cs | Adds Unix callback start helper that allocates argv/envp and integrates wait-state registration. |
| src/libraries/System.Diagnostics.Process/ref/System.Diagnostics.Process.csproj | Enables unsafe blocks for the ref assembly build due to pointer-typed API. |
| src/libraries/System.Diagnostics.Process/ref/System.Diagnostics.Process.cs | Updates ref surface with new public Process.Start overload and ProcessStartArguments. |
| src/libraries/Common/src/Interop/Unix/System.Native/Interop.ForkAndExecProcess.cs | Promotes argv/envp allocation helpers to internal for reuse. |
adamsitnik
left a comment
There was a problem hiding this comment.
@copilot please address my feedback
…local const, redirect stderr Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
adamsitnik
left a comment
There was a problem hiding this comment.
@copilot address the feedback where I've tagged you
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Addressed in |
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
adamsitnik
left a comment
There was a problem hiding this comment.
@copilot address my feedback
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
adamsitnik
left a comment
There was a problem hiding this comment.
@copilot fix following build failure:
src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Unix.cs(237,70): error CS9080: (NETCORE_ENGINEERING_TELEMETRY=Build) Use of variable 'resolvedPathBuffer' in this context may expose referenced variables outside of their declaration scope
And run all tests locally before pushing changes.
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Fixed in I addressed the CS9080 failure by making the Unix callback marshaller local Local validation run before pushing:
|
main PR
Description
Adds
Process.Start(ProcessStartInfo, Func<ProcessStartArguments, SafeProcessHandle>)to let callers create processes with custom platform APIs while still usingProcessinfrastructure (ReadAllText, async stream handling,WaitForExit, etc.).This PR also incorporates review feedback across the callback path and tests, including:
cmd /c echo ... 1>&2output formatting ("error \r\n"with trailing space before\r\n)ToInt32()conversions and passing raw handles asnintconsistentlyMost notably, callback executable-path data and callback argument lifetime behavior were updated based on feedback:
ProcessStartArguments.FileNamewas replaced with Unix-onlyProcessStartArguments.ResolvedPathResolvedPathis nowbyte*and annotated with[UnsupportedOSPlatform("windows")]args.ResolvedPathdirectly forposix_spawnProcessStartArgumentsis now aref structto constrain usage to callback lifetime by constructionLatest follow-up feedback updates:
Utf8StringMarshaller.ManagedToUnmanagedInfor resolved-path UTF-8 marshallingProcessUtils.ResolveValidPathProcessUtils.ResolvePathis now private and both Unix start paths useResolveValidPathProcessStartArgumentsXML docs were adjusted to keep summary wording generic and to describeResolvedPathas a resolved executable path (not absolute)CS9080) by constraining marshaller lifetime withscopedand keeping stack buffer usage in the same scopeCustomer Impact
Developers who need unsupported/native process creation mechanisms (for example custom
CreateProcess*/posix_spawnflows) can still rely on .NETProcessfeatures instead of reimplementing process I/O and lifetime handling themselves.Regression
No known product regression is being fixed. This is a new callback-based API path plus follow-up correctness and API-shape refinements from review feedback.
Testing
Validated with targeted builds/tests in this repo:
./dotnet.sh build src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj -c Release -v minimal /t:Compile /p:TargetFramework=net11.0-linux./dotnet.sh test src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csproj -c Release -f net11.0-unix -v minimal(Passed: 611, Failed: 0, Skipped: 5)Prerequisite setup used for local test execution:
./build.sh -subset clr+libs -rc Release -lc ReleaseRisk
Moderate. This change adds new public API surface and adjusts callback argument shape on Unix (
ResolvedPathpointer) and callback-lifetime constraints (ProcessStartArgumentsasref struct).Risk is mitigated by:
ResolveValidPath) to avoid divergence/duplicationUtf8StringMarshaller.ManagedToUnmanagedIn) in the callback pathToInt32()removal) and low riskPackage authoring no longer needed in .NET 9
IMPORTANT: Starting with .NET 9, you no longer need to edit a NuGet package's csproj to enable building and bump the version.
Keep in mind that we still need package authoring in .NET 8 and older versions.