Skip to content

Commit d108f16

Browse files
committed
Finish input writers to prevent dangling file descriptors
1 parent 66b3fc9 commit d108f16

File tree

2 files changed

+23
-7
lines changed

2 files changed

+23
-7
lines changed

Sources/Subprocess/PipeConfiguration.swift

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,6 @@ extension PipeConfiguration {
426426
private func runPipeline() async throws -> CollectedResult<Output, Error> {
427427
// Create a pipe for standard error
428428
let sharedErrorPipe = try FileDescriptor.pipe()
429-
let sharedErrorPipeOutput = FileDescriptorOutput(fileDescriptor: sharedErrorPipe.writeEnd, closeAfterSpawningProcess: false)
430429

431430
return try await withThrowingTaskGroup(of: CollectedPipeResult.self, returning: CollectedResult<Output, Error>.self) { group in
432431
// Collect error output from all stages
@@ -465,7 +464,7 @@ extension PipeConfiguration {
465464
configuration,
466465
input: self.input,
467466
output: .fileDescriptor(writeEnd, closeAfterSpawningProcess: true),
468-
error: sharedErrorPipeOutput
467+
error: FileDescriptorOutput(fileDescriptor: sharedErrorPipe.writeEnd, closeAfterSpawningProcess: false)
469468
)
470469

471470
taskResult = PipelineTaskResult.success(
@@ -565,6 +564,10 @@ extension PipeConfiguration {
565564
}
566565
}
567566

567+
// Close outputs in case the function did not
568+
try await outWriter.finish()
569+
try await errWriter.finish()
570+
568571
return 0
569572
}
570573

@@ -600,7 +603,7 @@ extension PipeConfiguration {
600603
configuration,
601604
input: .fileDescriptor(readEnd, closeAfterSpawningProcess: true),
602605
output: .fileDescriptor(writeEnd, closeAfterSpawningProcess: true),
603-
error: sharedErrorPipeOutput
606+
error: FileDescriptorOutput(fileDescriptor: sharedErrorPipe.writeEnd, closeAfterSpawningProcess: false)
604607
)
605608

606609
taskResult = PipelineTaskResult.success(
@@ -678,6 +681,10 @@ extension PipeConfiguration {
678681
}
679682
}
680683

684+
// Close outputs in case the function did not
685+
try await outWriter.finish()
686+
try await errWriter.finish()
687+
681688
return 0
682689
}
683690

@@ -712,7 +719,7 @@ extension PipeConfiguration {
712719
configuration,
713720
input: .fileDescriptor(readEnd, closeAfterSpawningProcess: true),
714721
output: self.output,
715-
error: sharedErrorPipeOutput
722+
error: FileDescriptorOutput(fileDescriptor: sharedErrorPipe.writeEnd, closeAfterSpawningProcess: false)
716723
)
717724
return PipelineTaskResult.success(lastIndex, SendableCollectedResult(finalResult))
718725
case .replaceStdout:
@@ -844,6 +851,11 @@ extension PipeConfiguration {
844851
return (retVal, .none)
845852
}
846853

854+
// FIXME: determine how best to handle these writers so that the function doesn't finish them, and it doesn't cause deadlock
855+
// Close outputs in case the function did not
856+
//try await outWriter.finish()
857+
//try await errWriter.finish()
858+
847859
var exitCode: UInt32 = 0
848860
var output: Output.OutputType? = nil
849861
for try await r in group {

Tests/SubprocessTests/PipeConfigurationTests.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ struct PipeConfigurationTests {
230230
}
231231

232232
// FIXME - these function tests are hanging on Linux
233-
#if os(macOS)
233+
#if !os(Windows)
234234
@Test func testBasicSwiftFunctionBeginning() async throws {
235235
let config =
236236
pipe { input, output, error in
@@ -261,7 +261,9 @@ struct PipeConfigurationTests {
261261
#expect(result.standardOutput?.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) == "Hello World")
262262
#expect(result.terminationStatus.isSuccess)
263263
}
264+
#endif
264265

266+
#if !os(Windows)
265267
@Test func testBasicSwiftFunctionMiddle() async throws {
266268
let config =
267269
pipe(
@@ -284,7 +286,7 @@ struct PipeConfigurationTests {
284286
}
285287
return 0
286288
} | Cat().configuration
287-
|> (
289+
|> (
288290
output: .string(limit: .max),
289291
error: .string(limit: .max)
290292
)
@@ -293,7 +295,9 @@ struct PipeConfigurationTests {
293295
#expect(result.standardOutput?.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) == "Hello World")
294296
#expect(result.terminationStatus.isSuccess)
295297
}
298+
#endif
296299

300+
#if !os(Windows)
297301
@Test func testBasicSwiftFunctionEnd() async throws {
298302
let config =
299303
pipe(
@@ -666,7 +670,7 @@ struct PipeConfigurationTests {
666670
}
667671

668672
// FIXME - this test is hanging on Linux
669-
#if os(macOS)
673+
#if !os(Windows)
670674
@Test func testMultiStageSwiftFunctionPipelineWithStringInput() async throws {
671675
let numbers = "10\n25\n7\n42\n13\n8\n99"
672676

0 commit comments

Comments
 (0)