@@ -324,6 +324,25 @@ extension Backtrace {
324
324
}
325
325
#endif
326
326
327
+ #if !hasFeature(Embedded) && SWT_TARGET_OS_APPLE && !SWT_NO_DYNAMIC_LINKING
328
+ /// A function provided by Core Foundation that copies the captured backtrace
329
+ /// from storage inside `CFError` or `NSError`.
330
+ ///
331
+ /// - Parameters:
332
+ /// - error: The error whose backtrace is desired.
333
+ ///
334
+ /// - Returns: The backtrace (as an instance of `NSArray`) captured by `error`
335
+ /// when it was created, or `nil` if none was captured. The caller is
336
+ /// responsible for releasing this object when done.
337
+ ///
338
+ /// This function was added in an internal Foundation PR
339
+ /// ([#2678](https://github.pie.apple.com/Cocoa/Foundation/pull/2678)) and is
340
+ /// not available on older systems.
341
+ private static let _CFErrorCopyCallStackReturnAddresses = symbol ( named: " _CFErrorCopyCallStackReturnAddresses " ) . map {
342
+ castCFunction ( at: $0, to: ( @convention( c) ( _ error: any Error) - > Unmanaged< AnyObject>? ) . self)
343
+ }
344
+ #endif
345
+
327
346
/// Whether or not Foundation provides a function that triggers the capture of
328
347
/// backtaces when instances of `NSError` or `CFError` are created.
329
348
///
@@ -339,7 +358,11 @@ extension Backtrace {
339
358
/// first time the value of this property is read.
340
359
static let isFoundationCaptureEnabled = {
341
360
#if !hasFeature(Embedded) && _runtime(_ObjC) && !SWT_NO_DYNAMIC_LINKING
342
- if Environment . flag ( named: " SWT_FOUNDATION_ERROR_BACKTRACING_ENABLED " ) == true {
361
+ // Check the environment variable; if it isn't set, enable if and only if
362
+ // the Core Foundation getter function is implemented.
363
+ let foundationBacktracesEnabled = Environment . flag ( named: " SWT_FOUNDATION_ERROR_BACKTRACING_ENABLED " )
364
+ ?? ( _CFErrorCopyCallStackReturnAddresses != nil )
365
+ if foundationBacktracesEnabled {
343
366
let _CFErrorSetCallStackCaptureEnabled = symbol ( named: " _CFErrorSetCallStackCaptureEnabled " ) . map {
344
367
castCFunction ( at: $0, to: ( @convention( c) ( DarwinBoolean) - > DarwinBoolean) . self)
345
368
}
@@ -422,11 +445,15 @@ extension Backtrace {
422
445
#if !hasFeature(Embedded)
423
446
@inline ( never)
424
447
init ? ( forFirstThrowOf error: any Error , checkFoundation: Bool = true ) {
425
- if checkFoundation && Self . isFoundationCaptureEnabled,
426
- let userInfo = error. _userInfo as? [ String : Any ] ,
427
- let addresses = userInfo [ " NSCallStackReturnAddresses " ] as? [ Address ] , !addresses. isEmpty {
428
- self . init ( addresses: addresses)
429
- return
448
+ if checkFoundation && Self . isFoundationCaptureEnabled {
449
+ if let addresses = Self . _CFErrorCopyCallStackReturnAddresses ? ( error) ? . takeRetainedValue ( ) as? [ Address ] {
450
+ self . init ( addresses: addresses)
451
+ return
452
+ } else if let userInfo = error. _userInfo as? [ String : Any ] ,
453
+ let addresses = userInfo [ " NSCallStackReturnAddresses " ] as? [ Address ] , !addresses. isEmpty {
454
+ self . init ( addresses: addresses)
455
+ return
456
+ }
430
457
}
431
458
432
459
let entry = Self . _errorMappingCache. withLock { cache in
0 commit comments