Skip to content

Commit 6e52b9a

Browse files
authored
Harden isKindOfClass: check (swiftlang#35797) (swiftlang#35823)
* Harden `isKindOfClass:` check We've seen some Obj-C NSProxy subclass implementations that are broken and will crash if you send them a standard `isKindOfClass:` message. This came out because the casting machinery is now more aggressive about trying different casting options which means some of these broken objects are being queried in new ways. This adds an additional check before calling `isKindOfClass:` to verify that this object is not using the default NSProxy selector routing. If it is, we just assume it's not whatever class is being tested for since we cannot do anything better. Resolves rdar://73799124 * Fixes from Mike Ash * Fix build
1 parent 57d601f commit 6e52b9a

File tree

1 file changed

+21
-2
lines changed

1 file changed

+21
-2
lines changed

stdlib/public/runtime/ErrorObject.mm

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,26 @@ typedef SWIFT_CC(swift) NSDictionary *(*GetErrorDefaultUserInfoFunction)(
542542

543543
extern "C" const ProtocolDescriptor PROTOCOL_DESCR_SYM(s5Error);
544544

545+
static IMP
546+
getNSProxyLookupMethod() {
547+
Class NSProxyClass = objc_lookUpClass("NSProxy");
548+
return class_getMethodImplementation(NSProxyClass, @selector(methodSignatureForSelector:));
549+
}
550+
551+
// A safer alternative to calling `isKindOfClass:` directly.
552+
static bool
553+
isKindOfClass(HeapObject *object, Class cls) {
554+
IMP NSProxyLookupMethod = SWIFT_LAZY_CONSTANT(getNSProxyLookupMethod());
555+
// People sometimes fail to override `methodSignatureForSelector:` in their
556+
// NSProxy subclasses, which causes `isKindOfClass:` to crash. Avoid that...
557+
Class objectClass = object_getClass((id)object);
558+
IMP objectLookupMethod = class_getMethodImplementation(objectClass, @selector(methodSignatureForSelector:));
559+
if (objectLookupMethod == NSProxyLookupMethod) {
560+
return false;
561+
}
562+
return [reinterpret_cast<id>(object) isKindOfClass: cls];
563+
}
564+
545565
bool
546566
swift::tryDynamicCastNSErrorObjectToValue(HeapObject *object,
547567
OpaqueValue *dest,
@@ -550,8 +570,7 @@ typedef SWIFT_CC(swift) NSDictionary *(*GetErrorDefaultUserInfoFunction)(
550570
Class NSErrorClass = getNSErrorClass();
551571

552572
// The object must be an NSError subclass.
553-
if (isObjCTaggedPointerOrNull(object) ||
554-
![reinterpret_cast<id>(object) isKindOfClass: NSErrorClass])
573+
if (isObjCTaggedPointerOrNull(object) || !isKindOfClass(object, NSErrorClass))
555574
return false;
556575

557576
id srcInstance = reinterpret_cast<id>(object);

0 commit comments

Comments
 (0)