Subprocess 1.0 Beta 1
Pre-release
Pre-release
This is the first beta release for Subprocess 1.0. This release contains the API surface we intend to ship with Subprocess 1.0, while the final API review is underway.
API Changes
Signal.init(rawValue:)is now public, allowing arbitrary signals to be constructed. by @iCharlesHu in #291run()body closures can now return non-Copyablevalues. by @iCharlesHu in #305- Restored
standardOutputandstandardErroras@available(*, deprecated, renamed:)aliases forcurrentStandardOutput/currentStandardError. by @marcprux in #288 SubprocessError.WindowsErroris now anenum. It no longer conforms toRawRepresentable(norawValue: DWORD); instead it has cases.ntStatus,.win32,.hresult, and.cRuntimewith matching initializers, so it can faithfully represent each Windows error subsystem. by @iCharlesHu in #299ExecutionResult.closureOutputrenamed toclosureResult. As part of allowingrun()body closures to return non-Copyablevalues,ExecutionResultis now conditionallyCopyableand gains a consumingtakeClosureResult(). by @iCharlesHu in #305- Windows
UserCredentialsis now internal.PlatformOptions.UserCredentialsandPlatformOptions.userCredentialshave been removed from the public API while the credentials-spawning design is deferred to post-1.0. by @jakepetroules in #285 - Removed the duplicate unlabeled
Configuration.init(_:arguments:…). Use theexecutable:-labeled initializer instead. by @iCharlesHu in #291
Behavior Changes
- Teardown now runs when the
run()body closure throws. Previously the child was left running until it exited on its own (which could hang indefinitely); the configured teardown sequence now terminates it. by @iCharlesHu in #292 - Environment variables are validated before spawning. Malformed keys/values (NUL bytes,
=or digit-leading keys, oversized Windows entries) now throw a descriptiveSubprocessError.spawnFailedinstead of spawning a child with a corrupt environment. by @iCharlesHu in #332 StandardInputWriterrejects writes afterfinish()with a clearSubprocessErrorrather than a cryptic "Bad file descriptor," andfinish()is now idempotent. by @iCharlesHu in #311
Bug Fixes
Reliability & Correctness
- Avoid a double-reap of the child after a
read()is interrupted byEINTR, which could otherwise reap an unrelated child on a recycled PID. by @broken-circle in #282 - Cancel a stalled standard-input writer when the child exits, fixing an indefinite hang when stdin is fed from a source that stalls. by @iCharlesHu in #306
- Retry transient
EAGAINwhen spawning (bounded, jittered backoff), fixing spuriousspawnFailederrors under high-concurrency / process-limit pressure. by @broken-circle in #312 - Prevent process-descriptor and zombie leaks when a spawn fails at
execve(). by @broken-circle in #319 - Prevent a
gid_tleak when spawning withprocessGroupID. by @broken-circle in #318 - Fix a potential crash in
fillNullTerminatedWideStringBuffer()under release optimization. by @broken-circle in #304
Windows
- Security: Escape
.bat/.cmdarguments againstcmd.execommand injection (the "BatBadBut" class, CVE-2024-24576 / CVE-2024-43402). by @iCharlesHu in #298 - Drain output still buffered in the pipe after a child exits and I/O is cancelled, and fix an overlapped-I/O bug where the kernel could write into a released buffer. by @broken-circle in #296
- Recover the final read buffer when output capture is cancelled by child termination, fixing silent truncation of up to ~16 KB of captured output. by @broken-circle in #325
- Fix a use-after-free on the standard-input write path when a child terminates mid-write. by @broken-circle in #336
- Sort the environment block passed to
CreateProcessW, as Windows requires, preventing a truncated/incorrect child environment. by @iCharlesHu in #307 - Fix
Environment.KeyComparable/Equatableconformance (case-insensitive equality had inconsistent ordering). by @broken-circle in #317, and fold keys to uppercase ordinally to match Windows sort order in
#320 - Stop leaking internal implementation details in
PlatformOptionsdescription output. by @broken-circle in #284
Platform Support
- Monitor process termination with kqueue instead of
DispatchSource, fixing FreeBSDpdforkchildren that never raiseSIGCHLDand removing theDispatchdependency entirely. by @iCharlesHu in #290 - Fix OpenBSD platform support. by @jakepetroules in #293
- Annotate
pthread_tout-parameter nullability, and relocate itsSendableconformance offOpaquePointer, on musl. by @broken-circle in #333, #334
Documentation
- Add a DocC catalog with task-based topics. by @broken-circle in #329
- Expand and standardize
InputandOutputprotocol documentation. by @broken-circle in #337 - Spelling, wording, and grammar updates. by @heckj in #328
- Fix README to use
strings()and document separator behavior. by @nenadvulic in #310 - Restructure the platform support table by testing category. by @jakepetroules in #294
- Add
SubprocessErrorsymbol links to error-throwing docs, and fix broken symbol links. by @broken-circle in #323, #322
Infrastructure, Testing & Internal
- Register each file descriptor once with epoll / kqueue, and remove the
_IODescriptorBoxworkaround. by @iCharlesHu in #314, @broken-circle in #321 - Adopt SE-0456
SpanandDataaccessors. by @broken-circle in #326 - Test old Linux kernels using QEMU. by @cmcgee1024 in #280
- Test hardening and CI updates: #267, #289, #295, #297, #300, #302, #308, #309, #315, #327, #331
Detailed Change List
- Mark Windows UserCredentials API as internal for now by @jakepetroules in #285
- Add back standardOutput and standardError as deprecated renamed properties by @marcprux in #288
- Avoid double-reap of child process after read
EINTRby @broken-circle in #282 - Monitor process termination with kqueue instead of DispatchSource by @iCharlesHu in #290
- Make Signal initializer public by @iCharlesHu in #291
- Avoid leaking implementation in
PlatformOptionsdescription by @broken-circle in #284 - Make
testConcurrentSlowExitsDoNotHang()deterministic and leak-free by @broken-circle in #289 - Fix OpenBSD platform support by @jakepetroules in #293
- Restructure platform support table by testing category by @jakepetroules in #294
- Run teardown sequence when the custom closure throws by @iCharlesHu in #292
- Make
testRunawayProcess()deterministic by @broken-circle in #295 - Add timeout to
testDoesNotReapUnrelatedChildProcess()by @broken-circle in #267 - Add regression test for unbounded stderr capture by @broken-circle in #297
- Update WindowsError to be able to represent NTSTATUS, HRESULT, errno, and Win32 error by @iCharlesHu in #299
- Escape .bat/.cmd arguments against cmd.exe injection on Windows by @iCharlesHu in #298
- Test old Linux kernels using Qemu by @cmcgee1024 in #280
- Make
testTeardownSequence()resilient to scheduling latency by @broken-circle in #300 - Fix crash in
fillNullTerminatedWideStringBuffer()by @broken-circle in #304 - Allow run body closures to return noncopyable values by @iCharlesHu in #305
- Drain buffered output on Windows after cancellation by @broken-circle in #296
- Add a timeout to the
test_linux_kerneljob by @broken-circle in #302 - Cancel a stalled standard-input writer when the child process exits by @iCharlesHu in #306
- Spawn
catin its own session intestSuspendResumeProcess()by @broken-circle in #308 - Docs: fix README to use strings(), document separator behavior by @nenadvulic in #310
- Sort Windows environment block alphabetically by @iCharlesHu in #307
- Reject writes after StandardInputWriter finishes with a clear error by @iCharlesHu in #311
- Add unit test to ensure Subprocess does not leak file descriptors when called sequentially by @iCharlesHu in #309
- Retry transient
EAGAINwhen spawning a subprocess by @broken-circle in #312 - Register each file descriptor once with epoll / kqueue by @iCharlesHu in #314
- Bump actions/checkout from 4 to 7 by @dependabot[bot] in #315
- Fix Windows
Environment.KeyComparableandEquatableconformance by @broken-circle in #317 - Prevent
gid_tleak when spawning withprocessGroupIDby @broken-circle in #318 - Prevent process-descriptor and zombie leaks on spawn exec failure by @broken-circle in #319
- Fix broken symbol links by @broken-circle in #322
- Fold
Environment.Keyto uppercase ordinally on Windows by @broken-circle in #320 - Remove
_IODescriptorBoxworkaround by @broken-circle in #321 - Add
SubprocessErrorsymbol links to error-throwing docs by @broken-circle in #323 - Adopt SE-0456
SpanandDataaccessors by @broken-circle in #326 - Remove experimental span feature from test target by @broken-circle in #327
- dropping the 6.1 requirement for building docs for this package by @heckj in #331
- Recover final read buffer when output capture is cancelled on Windows by @broken-circle in #325
- Add a DocC catalog with task-based topics by @broken-circle in #329
- Validate environment variables before spawning by @iCharlesHu in #332
- Annotate
pthread_tout-parameter nullability on musl by @broken-circle in #333 - Relocate
pthread_tSendableconformance offOpaquePointeron musl by @broken-circle in #334 - Spelling, wording, and grammar updates by @heckj in #328
- Expand and standardize
InputandOutputprotocol documentation by @broken-circle in #337 - Fix use-after-free when Windows input writing is cancelled by @broken-circle in #336
New Contributors
- @marcprux made their first contribution in #288
- @nenadvulic made their first contribution in #310
- @heckj made their first contribution in #331
Full Changelog: 0.5...1.0.0-beta.1