Analysing my code with the new exciting Thread Sanitizer tool from Xcode 8, in certain scenarios I'm experiencing unexpected data races in `deinit` of classes which protect the access to their properties with a synchronization primitive (a dispatch queue) .Given a class, with a "sync queue" and a synchronized member value:enum MyEnum {
case first(_: String)
case second(_: [String])
}
public class Foo {
private let _syncQueue = DispatchQueue(label: "foo-sync-queue", attributes: .serial)
private var _value: MyEnum = .first("")
public init() {
}
deinit {
}
public func modify(value: String) {
_syncQueue.async {
self._value = .first(value)
}
}
}What's not immediately obvious is the fact, that the deinit method must access the enum in order to figure out how to deallocate the underlying value.Suppose, method `modify` will be executed on Thread A. This causes the actual write operation to be executed on a thread, say M, which is synchronized with the `syncQueue`.It may happen that Thread A equals Thread M, but that is random.Now, suppose a reference to variable of type `Foo` exists in Thread B. It happens that this is the last strong reference to the variable. Now, when this variable ceases to exist, the `deinit` method of the variable will be called. This deinit reads from the memory store for member `_value`. This read operation is not synchronized with the sync queue. Since the executing thread happens to be not equal the thread M, where the previous write operation has been performed, a data race occurs.This data race is not easy to fix. I dare to state, it is even impossible in certain use cases. For example:Suppose there is a function which returns a new value of type Foo:func createFoo() -> FooAnd then:createFoo().modify(value: "Hello Data Race")The problem here is, that the live-time of the returned temporary is largely uncontrollable by the programmer. This prevents the programmer to determine _when_ the variable foo should be deallocated. And to be honest, a programmer shouldn't care about these details anyway!In practice, this creates a very reliable data race.This use case is not artificial in the functional paradigm. Actually, I'm having this issue, and I have no idea how to fix it - except there would be help with a corresponding language construct (e.g. let us implement the deinit function) - which does not currently exists.Any ideas are appreciated.
Post
Replies
Boosts
Views
Activity
I get an error:
error: Execution was interrupted, reason: signal SIGABRT.
The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.
when running the following minimal playground code in Xcode:
Swift
import SwiftUI
import PlaygroundSupport
struct Country: Identifiable {
var id: String { name }
var name: String
var flag: String
}
struct CountryView: View {
let name: String
let flag: String
var body: some View {
Text(name)
}
}
PlaygroundPage.current.setLiveView(
ForEach([Country(name: "Italy", flag: "italy")], id: \.id) { country in
CountryView(name: country.name, flag: country.flag)
}
)
This is for current Xcode Version 12.4 (12D4e), and beta3.
Note that Xcode does not crash. It's the playground execution.
Any hints for a workaround?
Additional notes:
Currently, playground seem to have a lot if issues and it's currently not usable as a whole - even without using SwiftUI there are a lot issues resulting in crashes, which I think is a very bad situation.
A crash log is generated when executing the playground.
Part of the crash log:
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
External Modification Warnings:
Debugger attached to process.
Application Specific Information:
abort() called
CoreSimulator 757.3 - Device: iPad Pro (9.7-inch) (28657173-2D19-4421-B084-2F4DDD658725) - Runtime: iOS 14.4 (18D46) - DeviceType: iPad Pro (9.7-inch)
AttributeGraph precondition failure: setting value during update: 5656.
Crash Log - https://developer.apple.com/forums/content/attachment/1d99662f-a766-4cd0-a002-a37f7de2dce0