Posts

Post not yet marked as solved
1 Replies
1.7k Views
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
Posted Last updated
.
Post not yet marked as solved
5 Replies
4.5k Views
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.
Posted Last updated
.