Skip to content

[SR-10547] Unavailable class with Swift-only protocol implementation causes a crash in getCanonicalTypeMetadata #52947

Open
@ghugues

Description

@ghugues
Previous ID SR-10547
Radar rdar://problem/50207523
Original Reporter @ghugues
Type Bug

Attachment: Download

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, 5.0Regression, RunTimeCrash
Assignee None
Priority Medium

md5: 7cca5f7cab0ff32756235f128b90b95f

Issue Description:

When a class that is only available starting with a given version of iOS implements a Swift only protocol, a crash occurs when testing conformance to this protocol on previous versions of iOS.

The following example crashes on all versions of iOS below iOS 12.0 :

protocol TestProtocol { }

@available(iOS 12.0, *)
class iOS12OnlySubclass: UITextInputPasswordRules, TestProtocol { }

func testCrash() {
    let instance = NSObject() // Can be anything
    _ = instance is TestProtocol // Crashes here
}

testCrash()

The UITextInputPasswordRules is just an example of a class that was introduced in iOS 12, any other class introduced in iOS 12 will cause the same crash.
iOS 12 is just an example of a version of iOS. If the class is only available in iOS n, then the crash occurs on all versions of iOS less than n.

This bug was introduced in Xcode 10.2 and does not seem to occur in Xcode 10.1
Compiled with Xcode 10.2, Swift 5.0 -> Crash
Compiled with Xcode 10.2, Swift 4.2 -> Crash
Compiled with Xcode 10.1, Swift 4.2 -> No crash

Workaround: If the protocol TestProtocol is declared @objc, no crash occurs.

Stacktrace :

* thread #​1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
    frame #​0: 0x0000000109a6c19f CoreFoundation`___forwarding___ + 1471
    frame #​1: 0x0000000109a6bb58 CoreFoundation`__forwarding_prep_0___ + 120
    frame #​2: 0x0000000105b93a14 libobjc.A.dylib`CALLING_SOME_+initialize_METHOD + 19
    frame #​3: 0x0000000105b93dae libobjc.A.dylib`_class_initialize + 276
    frame #​4: 0x0000000105b9a5e7 libobjc.A.dylib`lookUpImpOrForward + 225
    frame #​5: 0x0000000105baa3d4 libobjc.A.dylib`_objc_msgSend_uncached + 68
    frame #&#8203;6: 0x000000010527cde5 TestApp`type metadata accessor for iOS12OnlySubclass at <compiler-generated>:0
    frame #&#8203;7: 0x0000000108d0747c libswiftCore.dylib`swift::TargetProtocolConformanceDescriptor<swift::InProcess>::getCanonicalTypeMetadata() const + 172
    frame #&#8203;8: 0x0000000108d08564 libswiftCore.dylib`swift_conformsToSwiftProtocolImpl(swift::TargetMetadata<swift::InProcess> const*, swift::TargetProtocolDescriptor<swift::InProcess> const*, llvm::StringRef) + 292
    frame #&#8203;9: 0x0000000108d08348 libswiftCore.dylib`swift_conformsToProtocol + 152
    frame #&#8203;10: 0x0000000108cdcd8a libswiftCore.dylib`swift::_conformsToProtocol(swift::OpaqueValue const*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetProtocolDescriptorRef<swift::InProcess>, swift::TargetWitnessTable<swift::InProcess> const**) + 42
    frame #&#8203;11: 0x0000000108ce0b97 libswiftCore.dylib`_conformsToProtocols(swift::OpaqueValue const*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetExistentialTypeMetadata<swift::InProcess> const*, swift::TargetWitnessTable<swift::InProcess> const**) + 231
    frame #&#8203;12: 0x0000000108cdff69 libswiftCore.dylib`_dynamicCastToExistential(swift::OpaqueValue*, swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetExistentialTypeMetadata<swift::InProcess> const*, swift::DynamicCastFlags) + 489
  * frame #&#8203;13: 0x000000010527d02a TestApp`testCrash() at AppDelegate.swift:19:18

Console logs :

TestApp[18250:3491571] *** NSForwarding: warning: object 0x1052812f8 of class 'TestApp.iOS12OnlySubclass' does not implement methodSignatureForSelector: -- did you forget to declare the superclass of 'TestApp.iOS12OnlySubclass'?
TestApp[18250:3491571] *** NSForwarding: warning: object 0x1052812f8 of class 'TestApp.iOS12OnlySubclass' does not implement doesNotRecognizeSelector: -- abort

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugA deviation from expected or documented behavior. Also: expected but undesirable behavior.compilerThe Swift compiler itselfcrashBug: A crash, i.e., an abnormal termination of softwareregressionrun-time crashBug → crash: Swift code crashed during executionswift 5.0

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions