@@ -37,11 +37,7 @@ public struct Backtrace: Sendable {
37
37
/// The pointers in `addresses` are converted to instances of ``Address``. Any
38
38
/// `nil` addresses are represented as `0`.
39
39
public init ( addresses: some Sequence < UnsafeRawPointer ? > ) {
40
- self . init (
41
- addresses: addresses. lazy
42
- . map ( UInt . init ( bitPattern: ) )
43
- . map ( Address . init)
44
- )
40
+ self . addresses = addresses. map { Address ( UInt ( bitPattern: $0) ) }
45
41
}
46
42
47
43
/// Get the current backtrace.
@@ -61,33 +57,42 @@ public struct Backtrace: Sendable {
61
57
public static func current( maximumAddressCount addressCount: Int = 128 ) -> Self {
62
58
// NOTE: the exact argument/return types for backtrace() vary across
63
59
// platforms, hence the use of .init() when calling it below.
64
- let addresses = [ UnsafeRawPointer ? ] ( unsafeUninitializedCapacity : addressCount) { addresses, initializedCount in
65
- addresses . withMemoryRebound ( to : UnsafeMutableRawPointer ? . self ) { addresses in
60
+ withUnsafeTemporaryAllocation ( of : UnsafeMutableRawPointer ? . self , capacity : addressCount) { addresses in
61
+ var initializedCount = 0
66
62
#if SWT_TARGET_OS_APPLE
67
- if #available( _backtraceAsyncAPI, * ) {
68
- initializedCount = backtrace_async ( addresses. baseAddress!, addresses. count, nil )
69
- } else {
70
- initializedCount = . init( backtrace ( addresses. baseAddress!, . init( addresses. count) ) )
71
- }
72
- #elseif os(Linux)
73
- initializedCount = . init( backtrace ( addresses. baseAddress!, . init( addresses. count) ) )
63
+ if #available( _backtraceAsyncAPI, * ) {
64
+ initializedCount = backtrace_async ( addresses. baseAddress!, addresses. count, nil )
65
+ } else {
66
+ initializedCount = . init( clamping: backtrace ( addresses. baseAddress!, . init( clamping: addresses. count) ) )
67
+ }
74
68
#elseif os(Android)
75
- addresses. withMemoryRebound ( to: UnsafeMutableRawPointer . self) { addresses in
76
- initializedCount = . init( backtrace ( addresses. baseAddress!, . init( addresses. count) ) )
77
- }
69
+ initializedCount = addresses. withMemoryRebound ( to: UnsafeMutableRawPointer . self) { addresses in
70
+ . init( clamping: backtrace ( addresses. baseAddress!, . init( clamping: addresses. count) ) )
71
+ }
72
+ #elseif os(Linux)
73
+ initializedCount = . init( clamping: backtrace ( addresses. baseAddress!, . init( clamping: addresses. count) ) )
78
74
#elseif os(Windows)
79
- initializedCount = Int ( RtlCaptureStackBackTrace ( 0 , ULONG ( addresses. count) , addresses. baseAddress!, nil ) )
75
+ initializedCount = Int ( clamping : RtlCaptureStackBackTrace ( 0 , ULONG ( clamping : addresses. count) , addresses. baseAddress!, nil ) )
80
76
#elseif os(WASI)
81
- // SEE: https://github.com/WebAssembly/WASI/issues/159
82
- // SEE: https://github.com/swiftlang/swift/pull/31693
83
- initializedCount = 0
77
+ // SEE: https://github.com/WebAssembly/WASI/issues/159
78
+ // SEE: https://github.com/swiftlang/swift/pull/31693
84
79
#else
85
80
#warning("Platform-specific implementation missing: backtraces unavailable")
86
- initializedCount = 0
87
81
#endif
82
+
83
+ let endIndex = addresses. index ( addresses. startIndex, offsetBy: initializedCount)
84
+ #if _pointerBitWidth(_64)
85
+ // The width of a pointer equals the width of an `Address`, so we can just
86
+ // bitcast the memory rather than mapping through UInt first.
87
+ return addresses [ ..< endIndex] . withMemoryRebound ( to: Address . self) { addresses in
88
+ Self ( addresses: addresses)
88
89
}
90
+ #else
91
+ return addresses [ ..< endIndex] . withMemoryRebound ( to: UnsafeRawPointer ? . self) { addresses in
92
+ Self ( addresses: addresses)
93
+ }
94
+ #endif
89
95
}
90
- return Self ( addresses: addresses)
91
96
}
92
97
}
93
98
@@ -164,12 +169,12 @@ extension Backtrace {
164
169
/// - errorAddress: The error that is about to be thrown. This pointer
165
170
/// refers to an instance of `SwiftError` or (on platforms with
166
171
/// Objective-C interop) an instance of `NSError`.
167
- @Sendable private static func _willThrow( _ errorAddress: UnsafeMutableRawPointer ) {
172
+ /// - backtrace: The backtrace from where the error was thrown.
173
+ private static func _willThrow( _ errorAddress: UnsafeMutableRawPointer , from backtrace: Backtrace ) {
168
174
_oldWillThrowHandler. rawValue ? ( errorAddress)
169
175
170
176
let errorObject = unsafeBitCast ( errorAddress, to: ( any AnyObject & Sendable ) . self)
171
177
let errorID = ObjectIdentifier ( errorObject)
172
- let backtrace = Backtrace . current ( )
173
178
let newEntry = _ErrorMappingCacheEntry ( errorObject: errorObject, backtrace: backtrace)
174
179
175
180
_errorMappingCache. withLock { cache in
@@ -183,9 +188,15 @@ extension Backtrace {
183
188
184
189
/// The implementation of ``Backtrace/startCachingForThrownErrors()``, run
185
190
/// only once.
186
- private static let _startCachingForThrownErrors : Void = {
191
+ ///
192
+ /// This value is named oddly so that it shows up clearly in symbolicated
193
+ /// backtraces.
194
+ private static let __SWIFT_TESTING_IS_CAPTURING_A_BACKTRACE_FOR_A_THROWN_ERROR__ : Void = {
187
195
_oldWillThrowHandler. withLock { oldWillThrowHandler in
188
- oldWillThrowHandler = swt_setWillThrowHandler { _willThrow ( $0) }
196
+ oldWillThrowHandler = swt_setWillThrowHandler { errorAddress in
197
+ let backtrace = Backtrace . current ( )
198
+ _willThrow ( errorAddress, from: backtrace)
199
+ }
189
200
}
190
201
} ( )
191
202
@@ -196,7 +207,7 @@ extension Backtrace {
196
207
/// developer-supplied code to ensure that thrown errors' backtraces are
197
208
/// always captured.
198
209
static func startCachingForThrownErrors( ) {
199
- _startCachingForThrownErrors
210
+ __SWIFT_TESTING_IS_CAPTURING_A_BACKTRACE_FOR_A_THROWN_ERROR__
200
211
}
201
212
202
213
/// Flush stale entries from the error-mapping cache.
0 commit comments