Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ jobs:
ios_host_exclude_xcode_versions: '[{"xcode_version": "16.2"}, {"xcode_version": "16.3"}, {"xcode_version": "16.4"}]'
enable_wasm_sdk_build: true
enable_android_sdk_build: true
android_ndk_version: '["r28c"]'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be android_ndk_versions (plural) now; I changed it.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, r27d is the LTS NDK release, so maybe we should keep that and include r28?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r27d is the LTS NDK release, so maybe we should keep that and include r28?

We can't, as this new #available(Android feature in trunk and 6.3 only compiles with NDK 28 or later- the Bionic libc changed how it versioned its APIs by API level starting with NDK 28 and this feature requires that change- hence the drive to get all trunk/6.3 CI on NDK 28 or 29 now, in preparation for the likely next LTS NDK 30.

soundness:
name: Soundness
uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main
Expand Down
10 changes: 8 additions & 2 deletions Sources/Testing/SourceAttribution/Backtrace.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public struct Backtrace: Sendable {
self.addresses = addresses.map { Address(UInt(bitPattern: $0)) }
}

#if os(Android) && !SWT_NO_DYNAMIC_LINKING
#if compiler(<6.3) && os(Android)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why have you changed the order of conditionals here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No particular reason, just the perception that such compiler versioning is more important.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which conditional has more complexity, the compiler version check or the os check?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea what you mean by complexity in this context, I just figured that the compiler check is more generally known by Swift devs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, compiler() has special powers in the compiler (heh). If it evaluates to false, subsequent conditions are not even parsed. This means that you can write something like #if compiler(>=6.3) && objectFormat(ELF) and an older compiler won't complain that it doesn't know what objectFormat() is.

It's good to get into the habit of putting compiler() first for this reason.

/// The `backtrace()` function.
///
/// This function was added to Android with API level 33, which is higher than
Expand Down Expand Up @@ -76,7 +76,13 @@ public struct Backtrace: Sendable {
initializedCount = .init(clamping: backtrace(addresses.baseAddress!, .init(clamping: addresses.count)))
}
#elseif os(Android)
#if !SWT_NO_DYNAMIC_LINKING
#if compiler(>=6.3)
if #available(Android 33, *) {
initializedCount = addresses.withMemoryRebound(to: UnsafeMutableRawPointer.self) { addresses in
.init(clamping: backtrace(addresses.baseAddress!, .init(clamping: addresses.count)))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe an if let for baseAddress here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this almost always succeeds- unless the allocation up top fails?- so the unwrapping is a mere formality, but I'm just bringing back Jonathan's earlier code here: I didn't write this.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, for some reason (correct me I'm wrong) the closure gives you a buggy object with nil property references (such as a de-reference issue) maybe you will lead this into a SIGTRAP I think

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my experience, this always works and is a common idiom in the Swift corelibs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This unwrap cannot fail. Hence the forced unwrap. There is no point in an if let because we know the else case will never be executed.

! is considered acceptable style within the Swift toolchain under these circumstances.

}
}
#else
if let _backtrace {
initializedCount = .init(clamping: _backtrace(addresses.baseAddress!, .init(clamping: addresses.count)))
}
Expand Down