-
Notifications
You must be signed in to change notification settings - Fork 10.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
withUnsafeContinuation
can break actor isolation
#61485
Comments
Adding a lock solves the issue: func test_that_UnsafeContinuation_can_not_break_actor_isolation() async {
actor MyActor {
let lock = NSLock()
var count = 0
func zero() async {
lock.lock()
count += 1
await withUnsafeContinuation { continuation in
count -= 1
lock.unlock()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
continuation.resume()
}
}
}
}
do {
let actor = MyActor()
await withTaskGroup(of: Void.self) { group in
for _ in 0..<1_000 {
group.addTask {
await actor.zero()
}
}
}
let count = await actor.count
// Always good
XCTAssertEqual(count, 0)
}
} Not only this lock is not supposed to be necessary, but the compiler emits warnings, probably due to SE_0340 Unavailable From Async Attribute:
But this annoying warning is not what is interesting. What is interesting is that the lock workaround reveals that the source of the issue is probably the task resumed by the It is impossible to reason about the behavior of this resumed task, and its interactions with the current task. One has to assume the possibility of many kinds of bad interactions. According to this issue, it looks like the authors of the Swift actor runtime did not foresee how bad these interactions can be. |
The I believe you're seeing this behavior due to an unfortunate mismatch observed by others between the stdlib and compiler being when using Xcode 14.0.1 on macOS 12. In the Swift 5.6-era, there was no This shouldn't reproduce if you use Xcode 13 on macOS 12. If it does, then something else is going on. |
Thank you @kavon. This is an "unfortunate mismatch" indeed. I guess this issue is moot, since there is nothing to do, except avoiding Xcode 14.0 and 14.0.1 (maybe future versions as well, I don't know) to build macOS targets. Who knows how many people are doing just that just right now? 🤷♂️ |
The Xcode 14.1 betas do not have this problem and is available for download. |
It's difficult to grab a clear answer to this question, so... may I ask here? Betas will turn into RC and stable release eventually. And one can't submit an app to the App Store with a beta. Will we forever be stuck with Xcode 13.2 and Swift 5.6 if we target macOS before macOS 13 Ventura? |
No. The behavior you reported is nothing more than a bug specific to Xcode 14.0.x. |
Thank you. I can't tell you how many hours I've lost on this, and how many hypothesis I've built (garbage in, garbage out, right?). Xcode 14.0.x go to the Trash! |
Describe the bug
Hello,
withUnsafeContinuation
is able to break actor invariants that should be protected by actor isolation.Steps To Reproduce
The following test instantiates one actor, and performs as many increments as decrements of an isolated
count
property. It tests that the final value is the initial one: zero.Expected behavior
The above test passes without failure.
Environment (please fill out the following information)
Additional context
I stumbled upon this buggy (right?) behavior while exploring the difficulties using unsafe continuations in this discussion about the implementation of a counting semaphore for swift concurrency: groue/Semaphore#2 (reply in thread).
The text was updated successfully, but these errors were encountered: