Skip to content

Commit 408b5c9

Browse files
authored
Merge pull request #2553 from spevans/pr_sr_11699
SR-11699: Process: Closing standardInput before calling run() aborts with EBADF
2 parents f4214ef + f73518e commit 408b5c9

File tree

2 files changed

+70
-1
lines changed

2 files changed

+70
-1
lines changed

Foundation/Process.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,7 @@ open class Process: NSObject {
860860
for (new, old) in adddup2 {
861861
posix(_CFPosixSpawnFileActionsAddDup2(fileActions, old, new))
862862
}
863-
for fd in addclose {
863+
for fd in addclose.filter({ $0 >= 0 }) {
864864
posix(_CFPosixSpawnFileActionsAddClose(fileActions, fd))
865865
}
866866

TestFoundation/TestProcess.swift

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,73 @@ class TestProcess : XCTestCase {
696696
}
697697
}
698698

699+
func test_pipeCloseBeforeLaunch() {
700+
let process = Process()
701+
let stdInput = Pipe()
702+
let stdOutput = Pipe()
703+
704+
process.executableURL = xdgTestHelperURL()
705+
process.arguments = ["--cat"]
706+
process.standardInput = stdInput
707+
process.standardOutput = stdOutput
708+
709+
let string = "Hello, World"
710+
let stdInputPipe = stdInput.fileHandleForWriting
711+
XCTAssertNoThrow(try stdInputPipe.write(XCTUnwrap(string.data(using: .utf8))))
712+
stdInputPipe.closeFile()
713+
714+
XCTAssertNoThrow(try process.run())
715+
process.waitUntilExit()
716+
717+
let stdOutputPipe = stdOutput.fileHandleForReading
718+
do {
719+
let readData = try XCTUnwrap(stdOutputPipe.readToEnd())
720+
let readString = String(data: readData, encoding: .utf8)
721+
XCTAssertEqual(string, readString)
722+
} catch {
723+
XCTFail("\(error)")
724+
}
725+
}
726+
727+
func test_multiProcesses() {
728+
let source = Process()
729+
source.executableURL = xdgTestHelperURL()
730+
source.arguments = [ "--getcwd" ]
731+
732+
let cat1 = Process()
733+
cat1.executableURL = xdgTestHelperURL()
734+
cat1.arguments = [ "--cat" ]
735+
736+
let cat2 = Process()
737+
cat2.executableURL = xdgTestHelperURL()
738+
cat2.arguments = [ "--cat" ]
739+
740+
let pipe1 = Pipe()
741+
source.standardOutput = pipe1
742+
cat1.standardInput = pipe1
743+
744+
let pipe2 = Pipe()
745+
cat1.standardOutput = pipe2
746+
cat2.standardInput = pipe2
747+
748+
let pipe3 = Pipe()
749+
cat2.standardOutput = pipe3
750+
751+
XCTAssertNoThrow(try source.run())
752+
XCTAssertNoThrow(try cat1.run())
753+
XCTAssertNoThrow(try cat2.run())
754+
cat2.waitUntilExit()
755+
cat1.waitUntilExit()
756+
source.waitUntilExit()
757+
758+
do {
759+
let data = try XCTUnwrap(pipe3.fileHandleForReading.readToEnd())
760+
let pwd = String.init(decoding: data, as: UTF8.self).trimmingCharacters(in: CharacterSet(["\n", "\r"]))
761+
XCTAssertEqual(pwd, FileManager.default.currentDirectoryPath.standardizePath())
762+
} catch {
763+
XCTFail("\(error)")
764+
}
765+
}
699766

700767
static var allTests: [(String, (TestProcess) -> () throws -> Void)] {
701768
var tests = [
@@ -724,6 +791,8 @@ class TestProcess : XCTestCase {
724791
("test_redirect_all_using_nil", test_redirect_all_using_nil),
725792
("test_plutil", test_plutil),
726793
("test_currentDirectory", test_currentDirectory),
794+
("test_pipeCloseBeforeLaunch", test_pipeCloseBeforeLaunch),
795+
("test_multiProcesses", test_multiProcesses),
727796
]
728797

729798
#if !os(Windows)

0 commit comments

Comments
 (0)