Does detection of dynamic exclusivity violations depend on optimization level?

i have witnessed some code that is producing a runtime exclusivity violation, but it seems to only surface the runtime error when compiled with optimizations enabled. unfortunately i have not, as yet, found a small reproducer, but the gist is like:

func update(_ value: inout Value) {
  // self, value both structs
  value = Value(param: self.param) // traps within the (non-memberwise) init
}

is this an outcome that is expected (dynamic exclusivity violations differ based on optimization level), or should i try to reduce the issue to see if there's a bug?

Exclusivity violations are defined by the language. They can be hidden by optimization simply because optimization can prove that accesses are redundant. But never the other way around. If -O causes a trap, that's always worthy of a bug report. I can't tell whether the inout value is a member of self here. It would be great if you can come up with a reproducer, but I know hard that is with Swift.

4 Likes

thank you @Andrew_Trick. i did find a reproducer:

// build with:
//
// swiftc -parse-as-library -Onone
//  => does not trap
// swiftc -parse-as-library -O
//  => traps with exclusivity violation

import Observation

struct MyState {
    var _prop: String
    var prop: String
    {
        @storageRestrictions(initializes: _prop)
        init(initialValue) {
            _prop = initialValue
        }
        get {
            return _prop
        }
    }

    let registrar = ObservationRegistrar()

    init(prop: String) {
        self.prop = prop // crashes
        // self._prop = prop // does not
    }
}

class Node {
    var state = MyState(prop: "initial value")

    func update(_ body: (inout MyState) -> Void) {
        body(&state)
    }
}

func test_exclusivity() {
    let node = Node()
    node.update { state in
        state = MyState(prop: "new value")
    }
}

@main
enum App {
    static func main() {
        test_exclusivity()
    }
}

i have not yet dissected things enough to determine if it can be reproduced without the Observation code. to confirm, per your previous message, the fact that an exclusivity violation is not reported with -Onone but is with -O is a bug that i should file?

2 Likes

reported as: Dynamic memory exclusivity violations reported when using `-O` but not `-Onone` · Issue #83924 · swiftlang/swift · GitHub

1 Like

seems it is not related to Observation specifically (unsurprising), but appears to be reproducible when the client code contains certain types from a module built with library evolution:

// evo.swift
//
// build the following with something like:
// swiftc -emit-module -module-name LibraryEvoModule -emit-library -enable-library-evolution evo.swift -o build/libLibraryEvoModule.dylib

public struct ResilientStruct {
    public init() {}
}

// exclusivity.swift
//
// build with something like:
// swiftc -parse-as-library -O -I build -L build -lLibraryEvoModule exclusive.swift
//
// traps if built with -O, doesn't if built with -Onone

import LibraryEvoModule

struct MyState {
    var _prop: String
    var prop: String
    {
        @storageRestrictions(initializes: _prop)
        init(initialValue) {
            _prop = initialValue
        }
        get {
            return _prop
        }
    }

    let resilient = ResilientStruct()

    init(prop: String) {
        self.prop = prop // crashes
        // self._prop = prop // does not
    }
}

class Node {
    var state = MyState(prop: "initial value")

    func update(_ body: (inout MyState) -> Void) {
        body(&state)
    }
}

func test_exclusivity() {
    let node = Node()
    node.update { state in
        state = MyState(prop: "new value")
    }
}

@main
enum App {
    static func main() {
        test_exclusivity()
    }
}

it also appears to reproduce if the stored property is of certain types from the stdlib's Concurrency module, e.g. AsyncStream, ContinuousClock, etc.