Skip to content

Commit 5c0b60b

Browse files
committed
[Runtime] Fix swift_conformsToProtocol crashing on conformances to unavailable classes.
An extension on a class creates a conformance record that's always visible even when that class is not present at runtime. In that case, the type pointer in the conformance record is NULL. The runtime did not like this, and crashed. This fixes it to ignore such records instead. rdar://problem/54054895
1 parent 20b8d4c commit 5c0b60b

File tree

2 files changed

+67
-9
lines changed

2 files changed

+67
-9
lines changed

stdlib/public/runtime/ProtocolConformance.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -145,14 +145,15 @@ ProtocolConformanceDescriptor::getCanonicalTypeMetadata() const {
145145

146146
case TypeReferenceKind::DirectTypeDescriptor:
147147
case TypeReferenceKind::IndirectTypeDescriptor: {
148-
auto anyType = getTypeDescriptor();
149-
if (auto type = dyn_cast<TypeContextDescriptor>(anyType)) {
150-
if (!type->isGeneric()) {
151-
if (auto accessFn = type->getAccessFunction())
152-
return accessFn(MetadataState::Abstract).Value;
148+
if (auto anyType = getTypeDescriptor()) {
149+
if (auto type = dyn_cast<TypeContextDescriptor>(anyType)) {
150+
if (!type->isGeneric()) {
151+
if (auto accessFn = type->getAccessFunction())
152+
return accessFn(MetadataState::Abstract).Value;
153+
}
154+
} else if (auto protocol = dyn_cast<ProtocolDescriptor>(anyType)) {
155+
return _getSimpleProtocolTypeMetadata(protocol);
153156
}
154-
} else if (auto protocol = dyn_cast<ProtocolDescriptor>(anyType)) {
155-
return _getSimpleProtocolTypeMetadata(protocol);
156157
}
157158

158159
return nullptr;

test/Interpreter/availability_weak_linking.swift

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,18 @@
22
// RUN: cp -R %S/Inputs/FakeUnavailableObjCFramework.framework %t
33
// RUN: %target-clang -dynamiclib %S/Inputs/FakeUnavailableObjCFramework.m -fmodules -F %t -framework Foundation -o %t/FakeUnavailableObjCFramework.framework/FakeUnavailableObjCFramework
44
// RUN: %target-codesign %t/FakeUnavailableObjCFramework.framework/FakeUnavailableObjCFramework
5-
// RUN: %target-build-swift -F %t %s -o %t/UseWeaklinkedUnavailableObjCFramework
6-
// RUN: %target-build-swift -O -F %t %s -o %t/UseWeaklinkedUnavailableObjCFramework.opt
5+
// RUN: %target-build-swift-dylib(%t/%target-library-name(FakeUnavailableSwiftDylib)) -emit-module -emit-module-path %t/FakeUnavailableSwiftDylib.swiftmodule %S/Inputs/FakeUnavailableSwiftDylib.swift
6+
// RUN: %target-codesign %t/%target-library-name(FakeUnavailableSwiftDylib)
7+
// RUN: %target-build-swift %t/%target-library-name(FakeUnavailableSwiftDylib) -I %t -F %t %s -o %t/UseWeaklinkedUnavailableObjCFramework
8+
// RUN: %target-build-swift -O %t/%target-library-name(FakeUnavailableSwiftDylib) -I %t -F %t %s -o %t/UseWeaklinkedUnavailableObjCFramework.opt
79

810
// These tests emulate deploying back to an older OS where newer APIs are not
911
// available by linking to an Objective-C framework where APIs have been
1012
// annotated to only be available in the far future (version 1066.0 of all
1113
// platforms) and then moving the framework aside so that it can't be found
1214
// at run time.
1315
// RUN: mv %t/FakeUnavailableObjCFramework.framework %t/FakeUnavailableObjCFramework-MovedAside.framework
16+
// RUN: mv %t/%target-library-name(FakeUnavailableSwiftDylib) %t/%target-library-name(FakeUnavailableSwiftDylib)-MovedAside
1417

1518
// RUN: %target-codesign %t/UseWeaklinkedUnavailableObjCFramework
1619
// RUN: %target-codesign %t/UseWeaklinkedUnavailableObjCFramework.opt
@@ -24,6 +27,7 @@ import StdlibUnittest
2427

2528

2629
import FakeUnavailableObjCFramework
30+
import FakeUnavailableSwiftDylib
2731
import Foundation
2832

2933
// CHECK: Running
@@ -154,6 +158,59 @@ protocol SomeSwiftProtocol { }
154158
@available(OSX 1066.0, iOS 1066.0, watchOS 1066.0, tvOS 1066.0, *)
155159
extension UnavailableObjCClass : SomeSwiftProtocol {
156160
}
161+
@available(OSX 1066.0, iOS 1066.0, watchOS 1066.0, tvOS 1066.0, *)
162+
extension UnavailableSwiftClass : SomeSwiftProtocol {
163+
}
164+
165+
func checkSwiftProtocolConformance() {
166+
// Make sure the runtime doesn't crash in the presence of a conformance
167+
// record for a class that doesn't exsit at runtime.
168+
let x: Any = 42
169+
_blackHole(x as? SomeSwiftProtocol)
170+
}
171+
172+
checkSwiftProtocolConformance()
173+
174+
class ClassConformingToUnavailableSwiftProtocol : UnavailableSwiftProtocol {
175+
func someMethod() {
176+
print("Executed ClassConformingToUnavailableSwiftProtocol.someMethod()")
177+
}
178+
}
179+
180+
func useClassConformingToUnavailableSwiftProtocol() {
181+
let o = ClassConformingToUnavailableSwiftProtocol()
182+
o.someMethod()
183+
184+
if #available(OSX 1066.0, iOS 1066.0, watchOS 1066.0, tvOS 1066.0, *) {
185+
let oAsUP: UnavailableSwiftProtocol = o as UnavailableSwiftProtocol
186+
oAsUP.someMethod()
187+
}
188+
}
189+
190+
// CHECK-NEXT: Executed ClassConformingToUnavailableSwiftProtocol.someMethod()
191+
useClassConformingToUnavailableSwiftProtocol()
192+
193+
class ClassThatWillBeExtendedToConformToUnavailableSwiftProtocol {
194+
}
195+
196+
extension ClassThatWillBeExtendedToConformToUnavailableSwiftProtocol : UnavailableSwiftProtocol {
197+
func someMethod() {
198+
print("Executed ClassThatWillBeExtendedToConformToUnavailableSwiftProtocol.someMethod()")
199+
}
200+
}
201+
202+
func useClassThatWillBeExtendedToConformToUnavailableSwiftProtocol() {
203+
let o = ClassThatWillBeExtendedToConformToUnavailableSwiftProtocol()
204+
o.someMethod()
205+
206+
if #available(OSX 1066.0, iOS 1066.0, watchOS 1066.0, tvOS 1066.0, *) {
207+
let oAsUP: UnavailableSwiftProtocol = o as UnavailableSwiftProtocol
208+
oAsUP.someMethod()
209+
}
210+
}
211+
212+
// CHECK-NEXT: Executed ClassThatWillBeExtendedToConformToUnavailableSwiftProtocol.someMethod()
213+
useClassThatWillBeExtendedToConformToUnavailableSwiftProtocol()
157214

158215
// CHECK-NEXT: Done
159216
print("Done")

0 commit comments

Comments
 (0)