Description
Previous ID | SR-12080 |
Radar | rdar://problem/58997201 |
Original Reporter | @weissi |
Type | Bug |
Attachment: Download
Additional Detail from JIRA
Votes | 1 |
Component/s | Foundation |
Labels | Bug, Linux |
Assignee | None |
Priority | Medium |
md5: cd028eabf8a3fd19f398f6e16e95a8e4
Issue Description:
description
The following program just repeatedly spawns /usr/bin/env
and waits for both the stdout & stderr pipes to call the readabilityHandler
with a handle.availableData.isEmpty
(which means EOF).
On macOS it works just fine, on Linux it usually gets stuck fairly soon and it's always missing the call with handle.availableData.isEmpty
of stderr. We've never seen an invocation where the readabilityHandler
wasn't called for stdout.
This affects at least Swift 5.1, 5.2, and the latest master snapshot.
Credit to rignatus (JIRA User) for finding the initial issue that led to us debugging this together.
program
import Foundation
for i in 1..<1_000_000 {
fputs(".", stdout)
fflush(stdout)
if i % 10 == 0 {
fputs("\n", stdout)
}
let process = Process()
process.executableURL = URL(fileURLWithPath: "/usr/bin/env")
let g = DispatchGroup()
let stdoutPipe = Pipe()
let stderrPipe = Pipe()
process.standardOutput = stdoutPipe
process.standardError = stderrPipe
g.enter()
g.enter()
var numberOfCallsOut = 0
var numberOfCallsErr = 0
stderrPipe.fileHandleForReading.readabilityHandler = { handle in
if handle.availableData.isEmpty {
fputs("o", stdout)
fflush(stdout)
numberOfCallsOut += 1
//precondition(numberOfCalls == 1, "numberOfCalls: \(numberOfCalls)")
if numberOfCallsOut == 1 { g.leave() }
}
}
stdoutPipe.fileHandleForReading.readabilityHandler = { handle in
if handle.availableData.isEmpty {
fputs("e", stdout)
fflush(stdout)
numberOfCallsErr += 1
//precondition(numberOfCalls == 1, "numberOfCalls: \(numberOfCalls)")
if numberOfCallsErr == 1 { g.leave() }
}
}
try! process.run()
g.wait()
}
analysis
We did check the following things:
-
the process actually exited
-
the write end of the pipe is not open anymore (we checked by attaching lldb and calling
read
on it which promptly returned 0. We also checkedls -la /proc//fd/
andlsof -p PID
)
repro
on Linux
noformat
swift File.swift && ./File
noformat
on macOS (via docker)
# assuming File.swift is in the working directory
docker run --privileged --rm -v "$PWD:$PWD" -w "$PWD" -it norionomura/swift:nightly bash -c 'swiftc File.swift && ./File'