Skip to content

ABI incompatibility between Swift 5 & 6 with inherited protocols #75155

@KeithBauerANZ

Description

@KeithBauerANZ

Description

Where a library is built with Swift 5, with ABI resilience, and then called from Swift 6, inherited protocols cause a crash at runtime.

Rebuilding the framework with the Swift 6 compiler resolves the problem, but that shouldn't be necessary!

Reproduction

Build this as a dynamic library with ABI resilience and Swift 5,

public class Database {}

public protocol Reader: AnyObject, Sendable {
    func read<T>(_ closure: (Database) throws -> T) throws -> T
}

public protocol Writer: Reader {
    func write<T>(_ closure: (Database) throws -> T) throws -> T
}

public final class ReaderWriter: Writer {

    public init() {}

    public func write<T>(_ closure: (Database) throws -> T) throws -> T {
        return try closure(Database())
    }

    public func read<T>(_ closure: (Database) throws -> T) throws -> T {
        return try closure(Database())
    }

}

Then call it from code compile with Swift 6 (Swift 5 language mode):

                let db: any Writer = ReaderWriter()
                let result = try db.read { _ in
                    print("reading")
                    return [3: "hi"]
                }
                print("result: \(result)")

You'll crash in the call to read, because it's on the Reader protocol. Calls to write on the child Writer protocol will work fine:

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x8)
  * frame #0: 0x0000000104df3bb8 ABIBugTestFramework`dispatch thunk of ABIBugTestFramework.Reader.read<τ_0_0>((ABIBugTestFramework.Database) throws -> τ_1_0) throws -> τ_1_0 + 8
    frame #1: 0x0000000105372464 GRDBABIBug2.debug.dylib`closure #2 in ContentView.body.getter at ContentView.swift:33:37
    
(lldb) disassemble
ABIBugTestFramework`dispatch thunk of ABIBugTestFramework.Reader.read<τ_0_0>((ABIBugTestFramework.Database) throws -> τ_1_0) throws -> τ_1_0:
    0x104df3bb0 <+0>:  stp    x29, x30, [sp, #-0x10]!
    0x104df3bb4 <+4>:  mov    x29, sp
->  0x104df3bb8 <+8>:  ldr    x9, [x4, #0x8]
    0x104df3bbc <+12>: blr    x9
    0x104df3bc0 <+16>: ldp    x29, x30, [sp], #0x10
    0x104df3bc4 <+20>: ret    

Both projects to reproduce in case the above isn't sufficient: Archive.zip

Expected behavior

No crash!

Environment

Swift 5 (Xcode 15.4)
swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)
Target: arm64-apple-macosx14.0

Swift 6 (Xcode 16.0b3)
swift-driver version: 1.111.2 Apple Swift version 6.0 (swiftlang-6.0.0.5.15 clang-1600.0.22.6)
Target: arm64-apple-macosx14.0

Additional information

If there's any workaround for this, I'd love to hear it.

Metadata

Metadata

Assignees

Labels

IRGenLLVM IR generationaffects ABIFlag: Affects ABIbugA deviation from expected or documented behavior. Also: expected but undesirable behavior.compilerThe Swift compiler itselfcrashBug: A crash, i.e., an abnormal termination of softwaremultiple modulesFlag: An issue whose reproduction requires multiple modulesprotocolFeature → type declarations: Protocol declarationsregressionruntimeThe Swift Runtimeswift 6.0type declarationsFeature → declarations: Type declarations

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions