-
Notifications
You must be signed in to change notification settings - Fork 10.6k
Description
Description
Hi, together with @InversionSpaces we were stress testing the compiler and found the following data race that wasn't caught by the Swift compiler.
The following program has a data race. The counter is incremented two times concurrently, and thus the program is expected to run indefinitely printing 2, but at some point the program prints 1
Reproduction
class NonSendable {
var value: Int = 0
@discardableResult
func inc() -> Int {
value += 1
return value
}
}
actor MyActor {
var field = NonSendable()
func useValue(_ value: sending NonSendable) -> Task<Int, Never> {
Task { value.inc() }
}
}
func closureThatCapturesActorIsolatedStateTransfersExample(y: isolated MyActor, x: sending NonSendable) async -> Int {
let closure = {
y.field.inc()
return x.inc()
}
let task = await MyActor().useValue(x) // <-- We expect the compiler to prevent us passing `x` to another isolation
let b = closure()
let a = await task.result.get()
return max(a, b)
}
while true {
let x = NonSendable()
let result = await closureThatCapturesActorIsolatedStateTransfersExample(y: MyActor(), x: x)
print(result)
if result != 2 {
break
}
}Expected behavior
Compilation error on await MyActor().useValue(x) line
Environment
Apple Swift version 6.2.1 (swift-6.2.1-RELEASE)
Target: arm64-apple-macosx15.0
Build config: +assertions
Additional information
The example we found comes from us not understanding the third example in the evolution proposal, non-Sendable Closures section. https://github.com/swiftlang/swift-evolution/blob/c30efdf5145b95fb3b2d6a45d9d9f69d7e0dcaad/proposals/0414-region-based-isolation.md#captures
The proposal says that the example is unsafe while we believe that it is safe since everything is isolated to the same instance of MyActor. Our example is a slightly modified version where we extracted closureThatCapturesActorIsolatedStateTransfersExample function and used isolated parameter syntax instead of member function isolation syntax which leads the compiler to another extreme, and makes it think that everything is safe.
While we are still unsure about the original example from the evolution proposal (thus not raising any ticket yet), we are pretty confident that the problem we report in this GitHub issue is a bug.