From a2dded88b00c1df4f2a6d36f5f192738ac68c3db Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Sun, 5 Oct 2025 09:21:56 -0400 Subject: [PATCH] Dynamically look up `backtrace(3)` on Android. The `backtrace()` function on Android was added with API level 33, but at least some external Android builds target earlier Android NDKs, so we'll dynamically look up the function. If it's not present or dynamic loading isn't available, we just produce an empty backtrace. Resolves #1135. --- .../Testing/SourceAttribution/Backtrace.swift | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Sources/Testing/SourceAttribution/Backtrace.swift b/Sources/Testing/SourceAttribution/Backtrace.swift index fd7972cc4..6f6fcaabb 100644 --- a/Sources/Testing/SourceAttribution/Backtrace.swift +++ b/Sources/Testing/SourceAttribution/Backtrace.swift @@ -40,6 +40,16 @@ public struct Backtrace: Sendable { self.addresses = addresses.map { Address(UInt(bitPattern: $0)) } } +#if os(Android) && !SWT_NO_DYNAMIC_LINKING + /// The `backtrace()` function. + /// + /// This function was added to Android with API level 33, which is higher than + /// our minimum deployment target, so we look it up dynamically at runtime. + private static let _backtrace = symbol(named: "backtrace").map { + castCFunction(at: $0, to: (@convention(c) (UnsafeMutablePointer, CInt) -> CInt).self) + } +#endif + /// Get the current backtrace. /// /// - Parameters: @@ -66,9 +76,9 @@ public struct Backtrace: Sendable { initializedCount = .init(clamping: backtrace(addresses.baseAddress!, .init(clamping: addresses.count))) } #elseif os(Android) - initializedCount = addresses.withMemoryRebound(to: UnsafeMutableRawPointer.self) { addresses in - .init(clamping: backtrace(addresses.baseAddress!, .init(clamping: addresses.count))) - } +#if !SWT_NO_DYNAMIC_LINKING + initializedCount = .init(clamping: _backtrace?(addresses.baseAddress!, .init(clamping: addresses.count))) +#endif #elseif os(Linux) || os(FreeBSD) || os(OpenBSD) initializedCount = .init(clamping: backtrace(addresses.baseAddress!, .init(clamping: addresses.count))) #elseif os(Windows)