diff --git a/Sources/Testing/SourceAttribution/Backtrace.swift b/Sources/Testing/SourceAttribution/Backtrace.swift index a37916f71..6e32b3de2 100644 --- a/Sources/Testing/SourceAttribution/Backtrace.swift +++ b/Sources/Testing/SourceAttribution/Backtrace.swift @@ -37,11 +37,7 @@ public struct Backtrace: Sendable { /// The pointers in `addresses` are converted to instances of ``Address``. Any /// `nil` addresses are represented as `0`. public init(addresses: some Sequence) { - self.init( - addresses: addresses.lazy - .map(UInt.init(bitPattern:)) - .map(Address.init) - ) + self.addresses = addresses.map { Address(UInt(bitPattern: $0)) } } /// Get the current backtrace. @@ -61,33 +57,42 @@ public struct Backtrace: Sendable { public static func current(maximumAddressCount addressCount: Int = 128) -> Self { // NOTE: the exact argument/return types for backtrace() vary across // platforms, hence the use of .init() when calling it below. - let addresses = [UnsafeRawPointer?](unsafeUninitializedCapacity: addressCount) { addresses, initializedCount in - addresses.withMemoryRebound(to: UnsafeMutableRawPointer?.self) { addresses in + withUnsafeTemporaryAllocation(of: UnsafeMutableRawPointer?.self, capacity: addressCount) { addresses in + var initializedCount = 0 #if SWT_TARGET_OS_APPLE - if #available(_backtraceAsyncAPI, *) { - initializedCount = backtrace_async(addresses.baseAddress!, addresses.count, nil) - } else { - initializedCount = .init(backtrace(addresses.baseAddress!, .init(addresses.count))) - } -#elseif os(Linux) - initializedCount = .init(backtrace(addresses.baseAddress!, .init(addresses.count))) + if #available(_backtraceAsyncAPI, *) { + initializedCount = backtrace_async(addresses.baseAddress!, addresses.count, nil) + } else { + initializedCount = .init(clamping: backtrace(addresses.baseAddress!, .init(clamping: addresses.count))) + } #elseif os(Android) - addresses.withMemoryRebound(to: UnsafeMutableRawPointer.self) { addresses in - initializedCount = .init(backtrace(addresses.baseAddress!, .init(addresses.count))) - } + initializedCount = addresses.withMemoryRebound(to: UnsafeMutableRawPointer.self) { addresses in + .init(clamping: backtrace(addresses.baseAddress!, .init(clamping: addresses.count))) + } +#elseif os(Linux) + initializedCount = .init(clamping: backtrace(addresses.baseAddress!, .init(clamping: addresses.count))) #elseif os(Windows) - initializedCount = Int(RtlCaptureStackBackTrace(0, ULONG(addresses.count), addresses.baseAddress!, nil)) + initializedCount = Int(clamping: RtlCaptureStackBackTrace(0, ULONG(clamping: addresses.count), addresses.baseAddress!, nil)) #elseif os(WASI) - // SEE: https://github.com/WebAssembly/WASI/issues/159 - // SEE: https://github.com/swiftlang/swift/pull/31693 - initializedCount = 0 + // SEE: https://github.com/WebAssembly/WASI/issues/159 + // SEE: https://github.com/swiftlang/swift/pull/31693 #else #warning("Platform-specific implementation missing: backtraces unavailable") - initializedCount = 0 #endif + + let endIndex = addresses.index(addresses.startIndex, offsetBy: initializedCount) +#if _pointerBitWidth(_64) + // The width of a pointer equals the width of an `Address`, so we can just + // bitcast the memory rather than mapping through UInt first. + return addresses[..