Skip to content

Commit d7c0a61

Browse files
authored
Merge pull request #24618 from mikeash/self-awareness-class-struggle
[Runtime] Avoid +class overrides when initializing an ObjC class.
2 parents 6e53336 + 893e291 commit d7c0a61

File tree

5 files changed

+46
-1
lines changed

5 files changed

+46
-1
lines changed

stdlib/public/runtime/SwiftObject.mm

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1274,7 +1274,11 @@ id swift_dynamicCastObjCProtocolConditional(id object,
12741274
// Used when we have class metadata and we want to ensure a class has been
12751275
// initialized by the Objective-C runtime. We need to do this because the
12761276
// class "c" might be valid metadata, but it hasn't been initialized yet.
1277-
return [c class];
1277+
// Send a message that's likely not to be overridden to minimize potential
1278+
// side effects. Ignore the return value in case it is overridden to
1279+
// return something different. See SR-10463 for an example.
1280+
[c self];
1281+
return c;
12781282
}
12791283

12801284
static const ClassMetadata *
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#import <Foundation/Foundation.h>
2+
3+
// A class that overrides +class and +self to return nil.
4+
@interface EvilClass: NSObject
5+
@end
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#import "EvilClass.h"
2+
3+
@implementation EvilClass
4+
5+
+ (Class)class { return nil; }
6+
+ (id)self { return nil; }
7+
8+
@end
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module EvilClass {
2+
header "EvilClass.h"
3+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-clang -fobjc-arc %S/Inputs/ObjCEvilClassInitialization/EvilClass.m -c -o %t/EvilClass.o
3+
// RUN: %target-build-swift -I %S/Inputs/ObjCEvilClassInitialization/ %t/EvilClass.o %s -o %t/a.out
4+
// RUN: %target-codesign %t/a.out
5+
// RUN: %target-run %t/a.out
6+
7+
// REQUIRES: executable_test
8+
// REQUIRES: objc_interop
9+
10+
import EvilClass
11+
12+
import StdlibUnittest
13+
14+
let tests = TestSuite("ObjCEvilClassInitialization")
15+
16+
tests.test("GenericOnEvilClass") {
17+
struct Generic<T> {
18+
var type: T.Type { return T.self }
19+
}
20+
let g = Generic<EvilClass>()
21+
expectEqual("\(type(of: g))", "Generic<EvilClass>")
22+
expectEqual(g.type, EvilClass.self)
23+
}
24+
25+
runAllTests()

0 commit comments

Comments
 (0)