Skip to content

Commit 6f030af

Browse files
committed
Linux: reap child process if fork succeed but exec fails
1 parent 9c6703f commit 6f030af

File tree

6 files changed

+24
-15
lines changed

6 files changed

+24
-15
lines changed

Package.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import PackageDescription
66
var dep: [Package.Dependency] = [
77
.package(
88
url: "https://github.com/apple/swift-system",
9+
// Temporarily pin to 1.5.0 because 1.6.0 has a breaking change for Ubuntu Focal
10+
// https://github.com/apple/swift-system/issues/237
911
exact: "1.5.0"
1012
)
1113
]

Sources/Subprocess/Configuration.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -870,10 +870,10 @@ internal struct CreatedPipe: ~Copyable {
870870
guard let parentEnd, parentEnd != INVALID_HANDLE_VALUE else {
871871
// Since we created the pipe with `FILE_FLAG_FIRST_PIPE_INSTANCE`,
872872
// if there's already a pipe with the same name, GetLastError()
873-
// will be set to FILE_FLAG_FIRST_PIPE_INSTANCE. In this case,
873+
// will be set to ERROR_ACCESS_DENIED. In this case,
874874
// try again with a different name.
875875
let errorCode = GetLastError()
876-
guard errorCode != FILE_FLAG_FIRST_PIPE_INSTANCE else {
876+
guard errorCode != ERROR_ACCESS_DENIED else {
877877
continue
878878
}
879879
// Throw all other errors

Sources/Subprocess/IO/AsyncIO+Linux.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,16 @@ final class AsyncIO: Sendable {
214214
_ = _SubprocessCShims.write(currentState.shutdownFileDescriptor, &one, MemoryLayout<UInt64>.stride)
215215
// Cleanup the monitor thread
216216
pthread_join(currentState.monitorThread, nil)
217-
close(currentState.epollFileDescriptor)
218-
close(currentState.shutdownFileDescriptor)
217+
var closeError: CInt = 0
218+
if _SubprocessCShims.close(currentState.epollFileDescriptor) != 0 {
219+
closeError = errno
220+
}
221+
if _SubprocessCShims.close(currentState.shutdownFileDescriptor) != 0 {
222+
closeError = errno
223+
}
224+
if closeError != 0 {
225+
fatalError("Failed to close epollfd: \(String(cString: strerror(closeError)))")
226+
}
219227
}
220228

221229

Sources/Subprocess/Platforms/Subprocess+Linux.swift

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -131,14 +131,6 @@ extension Configuration {
131131
underlyingError: .init(rawValue: spawnError)
132132
)
133133
}
134-
func captureError(_ work: () throws -> Void) -> (any Swift.Error)? {
135-
do {
136-
try work()
137-
return nil
138-
} catch {
139-
return error
140-
}
141-
}
142134
// After spawn finishes, close all child side fds
143135
try self.safelyCloseMultiple(
144136
inputRead: inputReadFileDescriptor,
@@ -267,7 +259,7 @@ extension String {
267259
internal func monitorProcessTermination(
268260
forExecution execution: Execution
269261
) async throws -> TerminationStatus {
270-
try await withCheckedThrowingContinuation { continuation in
262+
return try await withCheckedThrowingContinuation { continuation in
271263
_childProcessContinuations.withLock { continuations in
272264
// We don't need to worry about a race condition here because waitid()
273265
// does not clear the wait/zombie state of the child process. If it sees

Sources/_SubprocessCShims/process_shims.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,14 @@ int _subprocess_fork_exec(
689689
// exec worked!
690690
close(pipefd[0]);
691691
return 0;
692-
} else if (read_rc > 0) {
692+
}
693+
// if we reach this point, exec failed.
694+
// Since we already have the child pid (fork succeed), reap the child
695+
// This mimic posix_spawn behavior
696+
siginfo_t info;
697+
waitid(P_PID, childPid, &info, WEXITED);
698+
699+
if (read_rc > 0) {
693700
// Child exec failed and reported back
694701
close(pipefd[0]);
695702
return childError;

Tests/SubprocessTests/SubprocessTests+Unix.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,7 @@ extension SubprocessUnixTests {
668668
var platformOptions = PlatformOptions()
669669
platformOptions.supplementaryGroups = Array(expectedGroups)
670670
let idResult = try await Subprocess.run(
671-
.path("/usr/bin/swift"),
671+
.name("swift"),
672672
arguments: [getgroupsSwift.string],
673673
platformOptions: platformOptions,
674674
output: .string

0 commit comments

Comments
 (0)