SIGSEGV in `withCheckedContinuation(isolation:function:_:)`

We started migrating our codebase to Swift 6 language mode. In one of our networking interface, we abstract our networking call to use the withCheckedContinuation(isolation:function:_:) while still supporting the Combine-based data task publisher. Recently we got some weird crash after migrating to Xcode 16. This crash is from tvOS 18.0:

Project
+0x92f868
$ss23withCheckedContinuation9isolation8function_xScA_pSgYi_SSyScCyxs5NeverOGXEtYalFTwb (<compiler-generated>)

Called from
libswift_Concurrency
+0x05e9e4
swift::runJobInEstablishedExecutorContext

Any pointers?

There are a couple related issues here. Start by updating to Xcode 16.1, though I've heard reports it doesn't fix all of the issues. Global `with*` Concurrency Functions Crash on Catalyst (Designed for iPad on macOS)

2 Likes

Ok. We plan to upgrade the Xcode as soon as it's available in the GitHub runner. Let's see how it goes.

GitHub's macOS images already have Xcode 16.1 deployed.

I believe it's the release candidate—the stable release has not yet been merged.

16.1RC is the release version, you don’t need an update.

We’re running into similar crashes in Swift 5 language mode on Xcode 16 and 16.1, but it appears to only be from clients running iOS 18 developer beta 1 through 4. As a result we’re having to roll back our CI system to Xcode 15.4, but lots of our developers are already on Sequoia so they can’t downgrade from Xcode 16.

The issue will never be fixed on those versions and there’s little reason to support them at all, so that seems unnecessary.

I feel similarly, but it had a large enough impact on crash free sessions during rollout that it would translate into an unacceptable revenue loss if crash rate were to hold steady as the rollout continued.

If you read the bottom of the thread Jon linked there is a fix for this: copy pasting the broken functions from the stdlib. We’ve been using it in production for weeks now with no problems.

1 Like

Is it possible to use that workaround for external packages as well somehow?

We have a few dependencies that are also triggering this issue.

I think it should be, but I don’t know enough about compilers and linkers to tell you how. What follows is going to be pure speculation on my part:

Assuming those libraries are prebuilt (if not, why not just fork them) you can probably find where they reference these symbols and modify those references to point to your own.

Whatever you use needs to only change the references in the code you shipped, and not any references to it in built in libraries that might be running in your process. Which rules out anything that might globally replace the definition, like @_dynamicReplacement or libraries like fishhook.

1 Like

We're seeing similar crashes coming from withThrowingTaskGroup, withCheckedThrowingContinuation and withCheckedContinuation.

Am I correct in assuming that these are all related issues and would require individual workaround for each one?

Yeah. I believe there is a pull request that adds isolation as a parameter to each of these functions, which is the root cause.

If memory serves, withTaskGroup is tricky because it uses a bunch of internal types. We don't call it in production in any of our apps, so we never bothered to fix it. But if you read the file it's defined in there's some stuff there that could maybe help you to call an older version?

As an aside, there are a few functions which don't crash despite having isolation added. We theorized that this is due to the ordering of the parameters being "safe," for example TaskLocal.withValue adds it in a position where presumably it is interpreted as being a String, and is subsequently never read by the body of withValue if I remember correctly. While withContinuation has it listed just before the closure itself, and therefore it's trying to use the isolation you pass in as the closure.

1 Like