Skip to content

Commit 077775e

Browse files
committed
don't rely on getdtablesize()
Android and possibly other UNIX systems lack getdtablesize() so let's try to use a better way of estimating the file descriptors we need to close post-fork, pre-exec by listing /proc/self/fd. If that fails, we fall back on getdtablesize or as a last resort a hard-coded 4096.
1 parent b45ce94 commit 077775e

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

Foundation/Process.swift

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,43 @@ extension CFSocketError {
6060
}
6161
#endif
6262

63+
#if !canImport(Darwin) && !os(Windows)
64+
private func findMaximumOpenFromProcSelfFD() -> CInt? {
65+
guard let dirPtr = opendir("/proc/self/fd") else {
66+
return nil
67+
}
68+
defer {
69+
closedir(dirPtr)
70+
}
71+
var highestFDSoFar = CInt(0)
72+
73+
while let dirEntPtr = readdir(dirPtr) {
74+
var entryName = dirEntPtr.pointee.d_name
75+
let thisFD = withUnsafeBytes(of: &entryName) { entryNamePtr -> CInt? in
76+
CInt(String(decoding: entryNamePtr.prefix(while: { $0 != 0 }), as: Unicode.UTF8.self))
77+
}
78+
highestFDSoFar = max(thisFD ?? -1, highestFDSoFar)
79+
}
80+
81+
return highestFDSoFar
82+
}
83+
84+
func findMaximumOpenFD() -> CInt {
85+
if let maxFD = findMaximumOpenFromProcSelfFD() {
86+
// the precise method worked, let's return this fd.
87+
return maxFD
88+
}
89+
90+
// We don't have /proc, let's go with the best estimate.
91+
#if os(Linux)
92+
return getdtablesize()
93+
#else
94+
return 4096
95+
#endif
96+
}
97+
#endif
98+
99+
63100
private func emptyRunLoopCallback(_ context : UnsafeMutableRawPointer?) -> Void {}
64101

65102

@@ -881,7 +918,7 @@ open class Process: NSObject {
881918
posix_spawnattr_init(&spawnAttrs)
882919
posix_spawnattr_setflags(&spawnAttrs, .init(POSIX_SPAWN_CLOEXEC_DEFAULT))
883920
#else
884-
for fd in 3 ..< getdtablesize() {
921+
for fd in 3 ... findMaximumOpenFD() {
885922
guard adddup2[fd] == nil &&
886923
!addclose.contains(fd) &&
887924
fd != taskSocketPair[1] else {

TestFoundation/xdgTestHelper/main.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,13 @@ func cat(_ args: ArraySlice<String>.Iterator) {
198198

199199
#if !os(Windows)
200200
func printOpenFileDescriptors() {
201-
for fd in 0..<getdtablesize() {
201+
let reasonableMaxFD: CInt
202+
#if os(Linux) || os(macOS)
203+
reasonableMaxFD = getdtablesize()
204+
#else
205+
reasonableMaxFD = 4096
206+
#endif
207+
for fd in 0..<reasonableMaxFD {
202208
if fcntl(fd, F_GETFD) != -1 {
203209
print(fd)
204210
}

0 commit comments

Comments
 (0)