Skip to content

Commit 60b66d1

Browse files
committed
Merge branch 'main' into SHGetKnownFolderPath-Continued
2 parents 733f2b0 + fefb1bf commit 60b66d1

File tree

19 files changed

+1948
-451
lines changed

19 files changed

+1948
-451
lines changed

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,11 @@ add_compile_definitions(
124124
if(CMAKE_SYSTEM_NAME STREQUAL Linux)
125125
check_symbol_exists(sched_getaffinity "sched.h" HAVE_SCHED_GETAFFINITY)
126126
add_compile_definitions($<$<COMPILE_LANGUAGE:C>:HAVE_SCHED_GETAFFINITY>)
127+
128+
# Pass -fno-omit-frame-pointer while compiling for better backtraces
129+
add_compile_options(
130+
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xcc -fno-omit-frame-pointer>"
131+
"$<$<COMPILE_LANGUAGE:C,CXX>:-fno-omit-frame-pointer>")
127132
endif()
128133

129134
# Precompute module triple for installation

Sources/CoreFoundation/CFPlatform.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ static inline void _CFSetProgramNameFromPath(const char *path) {
136136
#include <sys/exec.h>
137137
#endif
138138

139+
#if TARGET_OS_BSD && defined(__FreeBSD__)
140+
#include <sys/sysctl.h>
141+
#endif
142+
139143
const char *_CFProcessPath(void) {
140144
if (__CFProcessPath) return __CFProcessPath;
141145

@@ -230,6 +234,29 @@ const char *_CFProcessPath(void) {
230234
char *res = realpath(ps->ps_argvstr[0], NULL);
231235
argv0 = res? res: strdup(ps->ps_argvstr[0]);
232236
}
237+
#elif defined(__FreeBSD__)
238+
// see sysctl(3), pid == -1 means current process
239+
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
240+
int sysctl_ret = 0;
241+
size_t len = PATH_MAX + 1;
242+
argv0 = calloc(len, 1);
243+
244+
sysctl_ret = sysctl(mib, 4, argv0, &len, NULL, 0);
245+
246+
// in case for whatever reason the path is > PATH_MAX
247+
if (sysctl_ret == -1 && errno == ENOMEM) {
248+
// get size needed
249+
sysctl_ret = sysctl(mib, 4, NULL, &len, NULL, 0);
250+
if (sysctl_ret != -1) {
251+
argv0 = realloc(argv0, len);
252+
sysctl_ret = sysctl(mib, 4, argv0, &len, NULL, 0);
253+
}
254+
}
255+
256+
if (sysctl_ret == -1) {
257+
free(argv0);
258+
argv0 = NULL;
259+
}
233260
#endif
234261

235262
if (!__CFProcessIsRestricted() && argv0 && argv0[0] == '/') {
@@ -908,6 +935,9 @@ static void __CFTSDFinalize(void *arg) {
908935

909936
if (!arg || arg == CF_TSD_BAD_PTR) {
910937
// We've already been destroyed. The call above set the bad pointer again. Now we just return.
938+
#if defined(__FreeBSD__)
939+
__CFTSDSetSpecific(NULL);
940+
#endif
911941
return;
912942
}
913943

@@ -2287,9 +2317,10 @@ CF_EXPORT int _CFPosixSpawnFileActionsChdir(_CFPosixSpawnFileActionsRef file_act
22872317
// Glibc versions prior to 2.29 don't support posix_spawn_file_actions_addchdir_np, impacting:
22882318
// - Amazon Linux 2 (EoL mid-2025)
22892319
return ENOSYS;
2290-
#elif defined(__OpenBSD__)
2320+
#elif defined(__OpenBSD__) || defined(__QNX__)
22912321
// Currently missing as of:
22922322
// - OpenBSD 7.5 (April 2024)
2323+
// - QNX 8 (December 2023)
22932324
return ENOSYS;
22942325
#elif defined(__GLIBC__) || TARGET_OS_DARWIN || defined(__FreeBSD__) || (defined(__ANDROID__) && __ANDROID_API__ >= 34) || defined(__musl__)
22952326
// Pre-standard posix_spawn_file_actions_addchdir_np version available in:
@@ -2304,7 +2335,6 @@ CF_EXPORT int _CFPosixSpawnFileActionsChdir(_CFPosixSpawnFileActionsRef file_act
23042335
// Standardized posix_spawn_file_actions_addchdir version (POSIX.1-2024, June 2024) available in:
23052336
// - Solaris 11.4 (August 2018)
23062337
// - NetBSD 10.0 (March 2024)
2307-
// - QNX 8 (December 2023)
23082338
return posix_spawn_file_actions_addchdir((posix_spawn_file_actions_t *)file_actions, path);
23092339
#endif
23102340
}

Sources/Foundation/NSConcreteValue.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ internal class NSConcreteValue : NSValue, @unchecked Sendable {
9797
value.copyMemory(from: self._storage, byteCount: self._size)
9898
}
9999

100+
@available(*, deprecated, message: "On platforms without Objective-C autorelease pools, use withCString instead")
100101
override var objCType : UnsafePointer<Int8> {
101102
return NSString(self._typeInfo.name).utf8String! // XXX leaky
102103
}

Sources/Foundation/NSData.swift

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,10 +433,13 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
433433
#if os(WASI)
434434
// WASI does not have permission concept
435435
let permissions: Int? = nil
436+
// ReadingOptions.atomic won't be specified on WASI as it's marked unavailable
437+
var atomicWrite: Bool { false }
436438
#else
437439
let permissions = try? fm.attributesOfItem(atPath: path)[.posixPermissions] as? Int
440+
let atomicWrite = writeOptionsMask.contains(.atomic)
438441
#endif
439-
if writeOptionsMask.contains(.atomic) {
442+
if atomicWrite {
440443
let (newFD, auxFilePath) = try _NSCreateTemporaryFile(path)
441444
let fh = FileHandle(fileDescriptor: newFD, closeOnDealloc: true)
442445
do {
@@ -487,22 +490,38 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
487490

488491
/// Writes the data object's bytes to the file specified by a given path.
489492
/// NOTE: the 'atomically' flag is ignored if the url is not of a type the supports atomic writes
493+
#if os(WASI)
494+
@available(*, unavailable, message: "WASI does not support atomic file-writing as it does not have temporary directories")
495+
#endif
490496
open func write(toFile path: String, atomically useAuxiliaryFile: Bool) -> Bool {
497+
#if os(WASI)
498+
// WASI does not support atomic file-writing as it does not have temporary directories
499+
return false
500+
#else
491501
do {
492502
try write(toFile: path, options: useAuxiliaryFile ? .atomic : [])
493503
} catch {
494504
return false
495505
}
496506
return true
507+
#endif
497508
}
498509

499510
/// Writes the data object's bytes to the location specified by a given URL.
500511
/// NOTE: the 'atomically' flag is ignored if the url is not of a type the supports atomic writes
512+
#if os(WASI)
513+
@available(*, unavailable, message: "WASI does not support atomic file-writing as it does not have temporary directories")
514+
#endif
501515
open func write(to url: URL, atomically: Bool) -> Bool {
516+
#if os(WASI)
517+
// WASI does not support atomic file-writing as it does not have temporary directories
518+
return false
519+
#else
502520
if url.isFileURL {
503521
return write(toFile: url.path, atomically: atomically)
504522
}
505523
return false
524+
#endif
506525
}
507526

508527
/// Writes the data object's bytes to the location specified by a given URL.

Sources/Foundation/NSNumber.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,6 +1150,18 @@ open class NSNumber : NSValue, @unchecked Sendable {
11501150
}
11511151

11521152
open override var classForCoder: AnyClass { return NSNumber.self }
1153+
1154+
/// Provides a way for `plutil` to know if `CFPropertyList` has returned a literal `true`/`false` value, as opposed to a number which happens to have a value of 1 or 0.
1155+
@_spi(BooleanCheckingForPLUtil)
1156+
public var _exactBoolValue: Bool? {
1157+
if self === kCFBooleanTrue {
1158+
return true
1159+
} else if self === kCFBooleanFalse {
1160+
return false
1161+
} else {
1162+
return nil
1163+
}
1164+
}
11531165
}
11541166

11551167
extension CFNumber : _NSBridgeable {

Sources/Foundation/NSSpecialValue.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ internal class NSSpecialValue : NSValue, @unchecked Sendable {
9797
_value.encodeWithCoder(aCoder)
9898
}
9999

100+
@available(*, deprecated, message: "On platforms without Objective-C autorelease pools, use withCString instead")
100101
override var objCType : UnsafePointer<Int8> {
101102
let typeName = NSSpecialValue._objCTypeFromType(type(of: _value))
102103
return typeName!._bridgeToObjectiveC().utf8String! // leaky

Sources/Foundation/NSString.swift

Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
88
//
99

10-
10+
@_spi(SwiftCorelibsFoundation) @_exported import FoundationEssentials
1111
@_implementationOnly import CoreFoundation
1212
internal import Synchronization
1313

@@ -160,32 +160,19 @@ internal func _createRegexForPattern(_ pattern: String, _ options: NSRegularExpr
160160
return regex
161161
}
162162

163-
internal func _bytesInEncoding(_ str: NSString, _ encoding: String.Encoding, _ fatalOnError: Bool, _ externalRep: Bool, _ lossy: Bool) -> UnsafePointer<Int8>? {
164-
let theRange = NSRange(location: 0, length: str.length)
163+
// Caller must free, or leak, the pointer
164+
fileprivate func _allocateBytesInEncoding(_ str: NSString, _ encoding: String.Encoding) -> UnsafeMutableBufferPointer<Int8>? {
165+
let theRange: NSRange = NSRange(location: 0, length: str.length)
165166
var cLength = 0
166-
var used = 0
167-
var options: NSString.EncodingConversionOptions = []
168-
if externalRep {
169-
options.formUnion(.externalRepresentation)
170-
}
171-
if lossy {
172-
options.formUnion(.allowLossy)
173-
}
174-
if !str.getBytes(nil, maxLength: Int.max - 1, usedLength: &cLength, encoding: encoding.rawValue, options: options, range: theRange, remaining: nil) {
175-
if fatalOnError {
176-
fatalError("Conversion on encoding failed")
177-
}
167+
if !str.getBytes(nil, maxLength: Int.max - 1, usedLength: &cLength, encoding: encoding.rawValue, options: [], range: theRange, remaining: nil) {
178168
return nil
179169
}
180170

181-
let buffer = malloc(cLength + 1)!.bindMemory(to: Int8.self, capacity: cLength + 1)
182-
if !str.getBytes(buffer, maxLength: cLength, usedLength: &used, encoding: encoding.rawValue, options: options, range: theRange, remaining: nil) {
183-
fatalError("Internal inconsistency; previously claimed getBytes returned success but failed with similar invocation")
184-
}
171+
let buffer = UnsafeMutableBufferPointer<Int8>.allocate(capacity: cLength + 1)
172+
buffer.initialize(repeating: 0)
173+
_ = str.getBytes(buffer.baseAddress, maxLength: cLength, usedLength: nil, encoding: encoding.rawValue, options: [], range: theRange, remaining: nil)
185174

186-
buffer.advanced(by: cLength).initialize(to: 0)
187-
188-
return UnsafePointer(buffer) // leaked and should be autoreleased via a NSData backing but we cannot here
175+
return buffer
189176
}
190177

191178
internal func isALineSeparatorTypeCharacter(_ ch: unichar) -> Bool {
@@ -903,8 +890,13 @@ extension NSString {
903890
}
904891
}
905892

893+
@available(*, deprecated, message: "On platforms without Objective-C autorelease pools, use withCString instead")
906894
public var utf8String: UnsafePointer<Int8>? {
907-
return _bytesInEncoding(self, .utf8, false, false, false)
895+
guard let buffer = _allocateBytesInEncoding(self, .utf8) else {
896+
return nil
897+
}
898+
// leaked. On Darwin, freed via an autorelease
899+
return UnsafePointer<Int8>(buffer.baseAddress)
908900
}
909901

910902
public var fastestEncoding: UInt {
@@ -961,8 +953,24 @@ extension NSString {
961953
0, nil, 0, nil) == length
962954
}
963955

964-
public func cString(using encoding: UInt) -> UnsafePointer<Int8>? {
965-
return _bytesInEncoding(self, String.Encoding(rawValue: encoding), false, false, false)
956+
@available(*, deprecated, message: "On platforms without Objective-C autorelease pools, use withCString(encodedAs:_) instead")
957+
public func cString(using encoding: UInt) -> UnsafePointer<Int8>? {
958+
// leaked. On Darwin, freed via an autorelease
959+
guard let buffer = _allocateBytesInEncoding(self, String.Encoding(rawValue: encoding)) else {
960+
return nil
961+
}
962+
// leaked. On Darwin, freed via an autorelease
963+
return UnsafePointer<Int8>(buffer.baseAddress)
964+
}
965+
966+
internal func _withCString<T>(using encoding: UInt, closure: (UnsafePointer<Int8>?) -> T) -> T {
967+
let buffer = _allocateBytesInEncoding(self, String.Encoding(rawValue: encoding))
968+
let result = closure(buffer?.baseAddress)
969+
if let buffer {
970+
buffer.deinitialize()
971+
buffer.deallocate()
972+
}
973+
return result
966974
}
967975

968976
public func getCString(_ buffer: UnsafeMutablePointer<Int8>, maxLength maxBufferCount: Int, encoding: UInt) -> Bool {
@@ -1258,16 +1266,29 @@ extension NSString {
12581266
data = mData
12591267
}
12601268

1269+
#if os(WASI)
1270+
@available(*, unavailable, message: "WASI does not support atomic file-writing as it does not have temporary directories")
1271+
#endif
12611272
internal func _writeTo(_ url: URL, _ useAuxiliaryFile: Bool, _ enc: UInt) throws {
1273+
#if os(WASI)
1274+
throw CocoaError(.featureUnsupported)
1275+
#else
12621276
var data = Data()
12631277
try _getExternalRepresentation(&data, url, enc)
12641278
try data.write(to: url, options: useAuxiliaryFile ? .atomic : [])
1279+
#endif
12651280
}
12661281

1282+
#if os(WASI)
1283+
@available(*, unavailable, message: "WASI does not support atomic file-writing as it does not have temporary directories")
1284+
#endif
12671285
public func write(to url: URL, atomically useAuxiliaryFile: Bool, encoding enc: UInt) throws {
12681286
try _writeTo(url, useAuxiliaryFile, enc)
12691287
}
12701288

1289+
#if os(WASI)
1290+
@available(*, unavailable, message: "WASI does not support atomic file-writing as it does not have temporary directories")
1291+
#endif
12711292
public func write(toFile path: String, atomically useAuxiliaryFile: Bool, encoding enc: UInt) throws {
12721293
try _writeTo(URL(fileURLWithPath: path), useAuxiliaryFile, enc)
12731294
}
@@ -1669,3 +1690,14 @@ extension String : CVarArg, _CVarArgObject {
16691690
}
16701691
}
16711692
#endif
1693+
1694+
// Upcall from swift-foundation for conversion of less frequently-used encodings
1695+
@_dynamicReplacement(for: _cfStringEncodingConvert(string:using:allowLossyConversion:))
1696+
private func _cfStringEncodingConvert_corelibs_foundation(string: String, using encoding: UInt, allowLossyConversion: Bool) -> Data? {
1697+
return (string as NSString).data(using: encoding, allowLossyConversion: allowLossyConversion)
1698+
}
1699+
1700+
@_dynamicReplacement(for: _cfMakeStringFromBytes(_:encoding:))
1701+
private func _cfMakeStringFromBytes_corelibs_foundation(_ bytes: UnsafeBufferPointer<UInt8>, encoding: UInt) -> String? {
1702+
return NSString(bytes: bytes.baseAddress!, length: bytes.count, encoding: encoding) as? String
1703+
}

Sources/Foundation/NSStringAPI.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -633,9 +633,8 @@ extension StringProtocol {
633633
/// Returns a representation of the string as a C string
634634
/// using a given encoding.
635635
public func cString(using encoding: String.Encoding) -> [CChar]? {
636-
return withExtendedLifetime(_ns) {
637-
(s: NSString) -> [CChar]? in
638-
_persistCString(s.cString(using: encoding.rawValue))
636+
return _ns._withCString(using: encoding.rawValue) {
637+
_persistCString($0)
639638
}
640639
}
641640

Sources/FoundationNetworking/URLSession/libcurl/EasyHandle.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ import Dispatch
2929
// These helper functions avoid warnings about "will never be executed" code which checks the availability of the underlying libcurl features.
3030

3131
internal func curlInfoCAInfoSupported() -> Bool {
32-
NS_CURL_CURLINFO_CAINFO_SUPPORTED == 1
32+
CFURLSessionInfoCAINFO.value != CFURLSessionInfoNONE.value
3333
}
3434

3535
internal func maxHostConnectionsSupported() -> Bool {
36-
NS_CURL_MAX_HOST_CONNECTIONS_SUPPORTED == 1
36+
CFURLSessionMultiOptionMAX_HOST_CONNECTIONS.value != 0
3737
}
3838

3939
internal func xferInfoFunctionSupported() -> Bool {
40-
NS_CURL_XFERINFOFUNCTION_SUPPORTED == 1
40+
CFURLSessionOptionXFERINFOFUNCTION.value != 0
4141
}
4242

4343
/// Minimal wrapper around the [curl easy interface](https://curl.haxx.se/libcurl/c/)

Sources/_CFURLSessionInterface/CFURLSessionInterface.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,31 @@
2323
#include "CFString.h"
2424
#include <curl/curl.h>
2525

26+
#if !defined(LIBCURL_VERSION_MAJOR)
27+
#error "LIBCURL_VERSION_MAJOR not defined, missing curlver.h"
28+
#endif
29+
30+
// 7.84.0 or later
31+
#if LIBCURL_VERSION_MAJOR > 7 || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR > 84) || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR == 84 && LIBCURL_VERSION_PATCH >= 0)
32+
#define NS_CURL_CURLINFO_CAINFO_SUPPORTED 1
33+
#else
34+
#define NS_CURL_CURLINFO_CAINFO_SUPPORTED 0
35+
#endif
36+
37+
// 7.30.0 or later
38+
#if LIBCURL_VERSION_MAJOR > 7 || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR > 30) || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR == 30 && LIBCURL_VERSION_PATCH >= 0)
39+
#define NS_CURL_MAX_HOST_CONNECTIONS_SUPPORTED 1
40+
#else
41+
#define NS_CURL_MAX_HOST_CONNECTIONS_SUPPORTED 0
42+
#endif
43+
44+
// 7.32.0 or later
45+
#if LIBCURL_VERSION_MAJOR > 7 || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR > 32) || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR == 32 && LIBCURL_VERSION_PATCH >= 0)
46+
#define NS_CURL_XFERINFOFUNCTION_SUPPORTED 1
47+
#else
48+
#define NS_CURL_XFERINFOFUNCTION_SUPPORTED 0
49+
#endif
50+
2651
FILE* aa = NULL;
2752
CURL * gcurl = NULL;
2853

@@ -223,7 +248,7 @@ CFURLSessionEasyCode const CFURLSessionEasyCodeFTP_COULDNT_RETR_FILE = { CURLE_F
223248
#if LIBCURL_VERSION_MAJOR > 7 || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR > 67) || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR == 67 && LIBCURL_VERSION_PATCH >= 1)
224249
CFURLSessionEasyCode const CFURLSessionEasyCodeHTTP3 = { CURLE_HTTP3 };
225250
#else
226-
CFURLSessionEasyCode const CFURLSessionEasyCodeOBSOLETE20 = { CURLE_OBSOLETE20 };
251+
CFURLSessionEasyCode const CFURLSessionEasyCodeHTTP3 = { CURLE_OBSOLETE20 };
227252
#endif
228253
CFURLSessionEasyCode const CFURLSessionEasyCodeQUOTE_ERROR = { CURLE_QUOTE_ERROR };
229254
CFURLSessionEasyCode const CFURLSessionEasyCodeHTTP_RETURNED_ERROR = { CURLE_HTTP_RETURNED_ERROR };

0 commit comments

Comments
 (0)