swift_getWitnessTable EXC_BAD_ACCESS Xcode 11.3

I'm experiencing a runtime crash with Swift under macOS 10.14.6 and iOS 12. I'm using Xcode 11.3. The problem does not occur on macOS 10.15 or iOS 13. I'm building in Xcode 11.3

I've narrowed the problem down to a minimal example. The problem is triggered when accessing a type that conforms to (at least) two protocols: Identifiable and another Swift standard protocol. Using a default implementation also seems necessary.

Example:

public protocol A: Identifiable, ExpressibleByIntegerLiteral {
    init(_ id: Int)
}

extension A {
    public init(integerLiteral: Int) { self.init(integerLiteral) }
}

public struct AA: A {
    public var id: Int
    public init(_ id: Int) { self.id = id }
}

let sut = AA(42)     // EXC_BAD_ACCESS

Here's the stack:

#0 0x00007fff7decfb1f in swift_getWitnessTable ()
#1 0x0000000106ba31ec in lazy protocol witness table accessor for type AA and conformance AA ()
#2 0x0000000106ba3156 in instantiation function for generic protocol witness table for AA ()
#3 0x00007fff7ded00c9 in swift_getWitnessTable ()
#4 0x0000000106ba24ac in lazy protocol witness table accessor for type AA and conformance AA ()

Here's a package that illustrates the problem. It contains two slightly different unit tests which reliably crash (execute the unit tests in Xcode or the shell: swift test).

1 Like

I think it's because Identifiable is only available on iOS 13: swift/Identifiable.swift at main · apple/swift · GitHub

I came across the same issue in my app. It seems that using Identifiable below iOS 13 is possible:

struct User: Identifiable {
  let id: Int
}

But as soon as you want to use it with generics, the compiler complains:

func printID<T: Identifiable>(_ x: T) {
    print(x.id)
}

'Identifiable' is only available in iOS 13 or newer

Unfortunately, the compiler does not emit an error when implicitly using Identifiable as in this snippet:

protocol Foo: Identifiable {}

func printID<T: Foo>(_ x: T) {
    print(x.id)
}

The following will crash below iOS 13:

struct User: Foo {
  let id: Int
}

let user = User(id: 123)
printID(user) // EXC_BAD_ACCESS

The fix for us is to simply define Identifiable ourselves for now:

protocol Identifiable {
  associatedtype ID: Hashable
  var id: ID { get }
}

The fact that it is so easy to sneak this past the compiler is a bit frustrating.

Thanks, this explanation makes sense. I still think it should be considered a bug that the compiler does not catch this scenario.

You could file a bug at bugs.swift.org

1 Like