Skip to content

Commit a311f42

Browse files
authored
Merge pull request #24637 from mikeash/self-awareness-class-struggle-5.1
[5.1][Runtime] Avoid +class overrides when initializing an ObjC class.
2 parents 262dea5 + 2523778 commit a311f42

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
@@ -1269,7 +1269,11 @@ id swift_dynamicCastObjCProtocolConditional(id object,
12691269
// Used when we have class metadata and we want to ensure a class has been
12701270
// initialized by the Objective-C runtime. We need to do this because the
12711271
// class "c" might be valid metadata, but it hasn't been initialized yet.
1272-
return [c class];
1272+
// Send a message that's likely not to be overridden to minimize potential
1273+
// side effects. Ignore the return value in case it is overridden to
1274+
// return something different. See SR-10463 for an example.
1275+
[c self];
1276+
return c;
12731277
}
12741278

12751279
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)