Skip to content

Commit c3fc214

Browse files
authored
(130296407) Gracefully handle confstr failures (#728)
1 parent 6236e84 commit c3fc214

File tree

1 file changed

+14
-28
lines changed

1 file changed

+14
-28
lines changed

Sources/FoundationEssentials/String/String+Path.swift

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -462,36 +462,22 @@ extension String {
462462
return normalizedPath(with: String(decodingCString: wszPath, as: UTF16.self).standardizingPath)
463463
#else
464464
#if canImport(Darwin)
465-
let safe_confstr = { (name: Int32, buf: UnsafeMutablePointer<UInt8>?, len: Int) -> Int in
466-
// POSIX moment of weird: confstr() is one of those annoying APIs which
467-
// can return zero for both error and non-error conditions, so the only
468-
// way to disambiguate is to put errno in a known state before calling.
469-
errno = 0
470-
let result = confstr(name, buf, len)
471-
472-
// result == 0 is only error if errno is not zero. But, if there was an
473-
// error, bail; all possible errors from confstr() are Very Bad Things.
474-
let err = errno // only read errno once in the failure case.
475-
precondition(result > 0 || err == 0, "Unexpected confstr() error: \(err)")
476-
477-
// This is extreme paranoia and should never happen; this would mean
478-
// confstr() returned < 0, which would only happen for impossibly long
479-
// sizes of value or long-dead versions of the OS.
480-
assert(result >= 0, "confstr() returned impossible result: \(result)")
481-
482-
return result
483-
}
484-
485-
let length: Int = safe_confstr(_CS_DARWIN_USER_TEMP_DIR, nil, 0)
465+
// If confstr returns 0 it either failed or the variable had no content
466+
// If the variable had no content, we should continue on below
467+
// If it fails, we should also silently ignore the error and continue on below. This API can fail for non-programmer reasons such as the device being out of storage space when libSystem attempts to create the directory
468+
let length: Int = confstr(_CS_DARWIN_USER_TEMP_DIR, nil, 0)
486469
if length > 0 {
487-
var buffer: [UInt8] = .init(repeating: 0, count: length)
488-
let final_length = safe_confstr(_CS_DARWIN_USER_TEMP_DIR, &buffer, buffer.count)
489-
490-
assert(length == final_length, "Value of _CS_DARWIN_USER_TEMP_DIR changed?")
491-
if length > 0 && length < buffer.count {
492-
return buffer.withUnsafeBufferPointer { b in
493-
String(bytes: b, encoding: .utf8)!
470+
let result: String? = withUnsafeTemporaryAllocation(of: UInt8.self, capacity: length) { buffer in
471+
let finalLength = confstr(_CS_DARWIN_USER_TEMP_DIR, buffer.baseAddress!, buffer.count)
472+
assert(length == finalLength, "Value of _CS_DARWIN_USER_TEMP_DIR changed?")
473+
if length > 0 && length < buffer.count {
474+
return String(decoding: buffer, as: UTF8.self)
494475
}
476+
return nil
477+
}
478+
479+
if let result {
480+
return result
495481
}
496482
}
497483
#endif

0 commit comments

Comments
 (0)