Skip to content

Commit f817ce5

Browse files
authored
Dynamically look up backtrace(3) on Android. (#1356)
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. See: https://cs.android.com/android/_/android/platform/bionic/+/731631f300090436d7f5df80d50b6275c8c60a93:libc/include/execinfo.h;l=52 Resolves #1135. ### Checklist: - [x] Code and documentation should follow the style of the [Style Guide](https://github.com/apple/swift-testing/blob/main/Documentation/StyleGuide.md). - [x] If public symbols are renamed or modified, DocC references should be updated.
1 parent 90e08ac commit f817ce5

File tree

1 file changed

+13
-3
lines changed

1 file changed

+13
-3
lines changed

Sources/Testing/SourceAttribution/Backtrace.swift

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ public struct Backtrace: Sendable {
4040
self.addresses = addresses.map { Address(UInt(bitPattern: $0)) }
4141
}
4242

43+
#if os(Android) && !SWT_NO_DYNAMIC_LINKING
44+
/// The `backtrace()` function.
45+
///
46+
/// This function was added to Android with API level 33, which is higher than
47+
/// our minimum deployment target, so we look it up dynamically at runtime.
48+
private static let _backtrace = symbol(named: "backtrace").map {
49+
castCFunction(at: $0, to: (@convention(c) (UnsafeMutablePointer<UnsafeMutableRawPointer?>, CInt) -> CInt).self)
50+
}
51+
#endif
52+
4353
/// Get the current backtrace.
4454
///
4555
/// - Parameters:
@@ -66,9 +76,9 @@ public struct Backtrace: Sendable {
6676
initializedCount = .init(clamping: backtrace(addresses.baseAddress!, .init(clamping: addresses.count)))
6777
}
6878
#elseif os(Android)
69-
initializedCount = addresses.withMemoryRebound(to: UnsafeMutableRawPointer.self) { addresses in
70-
.init(clamping: backtrace(addresses.baseAddress!, .init(clamping: addresses.count)))
71-
}
79+
#if !SWT_NO_DYNAMIC_LINKING
80+
initializedCount = .init(clamping: _backtrace?(addresses.baseAddress!, .init(clamping: addresses.count)))
81+
#endif
7282
#elseif os(Linux) || os(FreeBSD) || os(OpenBSD)
7383
initializedCount = .init(clamping: backtrace(addresses.baseAddress!, .init(clamping: addresses.count)))
7484
#elseif os(Windows)

0 commit comments

Comments
 (0)