]> git.saurik.com Git - apple/objc4.git/blob - test/swiftMetadataInitializerRealloc.m
objc4-818.2.tar.gz
[apple/objc4.git] / test / swiftMetadataInitializerRealloc.m
1 /*
2 TEST_CONFIG MEM=mrc
3 TEST_BUILD
4 $C{COMPILE} $DIR/swiftMetadataInitializerRealloc-dylib1.m -o libswiftMetadataInitializerRealloc-dylib1.dylib -dynamiclib -Wno-deprecated-objc-pointer-introspection
5 $C{COMPILE} $DIR/swiftMetadataInitializerRealloc-dylib2.m -o libswiftMetadataInitializerRealloc-dylib2.dylib -dynamiclib -L. -lswiftMetadataInitializerRealloc-dylib1
6 $C{COMPILE} $DIR/swiftMetadataInitializerRealloc.m -o swiftMetadataInitializerRealloc.exe -L. -lswiftMetadataInitializerRealloc-dylib1 -Wno-deprecated-objc-pointer-introspection
7 END
8 */
9
10 #include "test.h"
11 #include "swift-class-def.m"
12
13
14 // _objc_swiftMetadataInitializer hooks for the classes in swift-class-def.m
15
16 Class initSuper(Class cls __unused, void *arg __unused)
17 {
18 // This test provokes objc's callback out of superclass order.
19 // SwiftSub's init is first. SwiftSuper's init is never called.
20
21 fail("SwiftSuper's init should not have been called");
22 }
23
24 bool isRealized(Class cls)
25 {
26 // check the is-realized bits directly
27
28 #if __LP64__
29 # define mask (~(uintptr_t)7)
30 #else
31 # define mask (~(uintptr_t)3)
32 #endif
33 #define RW_REALIZED (1<<31)
34
35 uintptr_t rw = ((uintptr_t *)cls)[4] & mask; // class_t->data
36 return ((uint32_t *)rw)[0] & RW_REALIZED; // class_rw_t->flags
37 }
38
39 SWIFT_CLASS(SwiftSuper, NSObject, initSuper);
40 SWIFT_CLASS(RealSwiftSub, SwiftSuper, initSub);
41
42 SWIFT_STUB_CLASS(SwiftSub, initSub);
43
44 OBJC_EXPORT _Nullable Class
45 objc_loadClassref(_Nullable Class * _Nonnull clsref);
46
47 static int SubInits = 0;
48 Class initSub(Class cls, void *arg)
49 {
50 testprintf("initSub callback\n");
51
52 testassert(SubInits == 0);
53 SubInits++;
54 testassert(arg == nil);
55 testassert(cls == RawSwiftSub);
56 testassert(!isRealized(RawSwiftSuper));
57
58 // Copy the class to the heap to ensure they're registered properly.
59 // Classes in the data segment are automatically "known" even if not
60 // added as a known class. Swift dynamically allocates classes from
61 // a statically allocated space in the dylib, then allocates from
62 // the heap after it runs out of room there. Code that only works
63 // when the class is in a dylib can fail a long time down the road
64 // when something finally exceeds the capacity of that space.
65 // Example: rdar://problem/50707074
66 Class HeapSwiftSub = (Class)malloc(OBJC_MAX_CLASS_SIZE);
67 memcpy(HeapSwiftSub, RawRealSwiftSub, OBJC_MAX_CLASS_SIZE);
68 // Re-sign the isa and super pointers in the new location.
69 ((Class __ptrauth_objc_isa_pointer *)(void *)HeapSwiftSub)[0] = ((Class __ptrauth_objc_isa_pointer *)(void *)RawRealSwiftSub)[0];
70 ((Class __ptrauth_objc_super_pointer *)(void *)HeapSwiftSub)[1] = ((Class __ptrauth_objc_super_pointer *)(void *)RawRealSwiftSub)[1];
71
72 testprintf("initSub beginning _objc_realizeClassFromSwift\n");
73 _objc_realizeClassFromSwift(HeapSwiftSub, cls);
74 testprintf("initSub finished _objc_realizeClassFromSwift\n");
75
76 testassert(isRealized(RawSwiftSuper));
77 testassert(isRealized(HeapSwiftSub));
78
79 testprintf("Returning reallocated class %p\n", HeapSwiftSub);
80
81 return HeapSwiftSub;
82 }
83
84
85 @interface SwiftSub (Addition)
86 - (int)number;
87 @end
88 @implementation SwiftSub (Addition)
89 - (int)number { return 42; }
90 @end
91
92 @interface NSObject (DylibCategories)
93 - (const char *)dylib1ACategoryInSameDylib;
94 - (const char *)dylib1BCategoryInSameDylib;
95 - (const char *)dylib1ACategoryInOtherDylib;
96 - (const char *)dylib1BCategoryInOtherDylib;
97 - (const char *)dylib1ACategoryInApp;
98 - (const char *)dylib1BCategoryInApp;
99 + (const char *)dylib1ACategoryInAppClassMethod;
100 + (const char *)dylib1BCategoryInAppClassMethod;
101 + (void)testFromOtherDylib;
102 @end
103
104 extern int Dylib1AInits;
105 extern int Dylib1BInits;
106 SWIFT_STUB_CLASSREF(SwiftDylib1A);
107 SWIFT_STUB_CLASSREF(SwiftDylib1B);
108 void Dylib1Test(void);
109
110 @interface SwiftDylib1A: NSObject @end
111 @interface SwiftDylib1B: NSObject @end
112
113 @implementation SwiftDylib1A (Category)
114 - (const char *)dylib1ACategoryInApp { return "dylib1ACategoryInApp"; }
115 + (const char *)dylib1ACategoryInAppClassMethod { return "dylib1ACategoryInAppClassMethod"; }
116 @end
117 @implementation SwiftDylib1B (Category)
118 - (const char *)dylib1BCategoryInApp { return "dylib1BCategoryInApp"; }
119 + (const char *)dylib1BCategoryInAppClassMethod { return "dylib1BCategoryInAppClassMethod"; }
120 @end
121
122
123 int main()
124 {
125 #define LOG(fmt, expr) testprintf(#expr " is " #fmt "\n", expr);
126 LOG(%p, SwiftSubClassref);
127 Class loadedSwiftSub = objc_loadClassref(&SwiftSubClassref);
128 LOG(%p, SwiftSubClassref);
129 LOG(%p, loadedSwiftSub);
130 LOG(%p, [loadedSwiftSub class]);
131 LOG(%p, [loadedSwiftSub superclass]);
132 LOG(%p, [RawSwiftSuper class]);
133
134 id obj = [[loadedSwiftSub alloc] init];
135 LOG(%p, obj);
136 LOG(%d, [obj number]);
137
138 LOG(%p, SwiftDylib1AClassref);
139 testassert(Dylib1AInits == 0);
140 testassert((uintptr_t)SwiftDylib1AClassref & 1);
141 Class SwiftDylib1A = objc_loadClassref(&SwiftDylib1AClassref);
142 testassert(((uintptr_t)SwiftDylib1AClassref & 1) == 0);
143 testassert(SwiftDylib1A == [SwiftDylib1A class]);
144 testassert(SwiftDylib1A == SwiftDylib1AClassref);
145 testassert(Dylib1AInits == 1);
146 LOG(%p, SwiftDylib1A);
147
148 LOG(%p, SwiftDylib1BClassref);
149 testassert(Dylib1BInits == 0);
150 testassert((uintptr_t)SwiftDylib1BClassref & 1);
151 Class SwiftDylib1B = objc_loadClassref(&SwiftDylib1BClassref);
152 testassert(((uintptr_t)SwiftDylib1BClassref & 1) == 0);
153 testassert(SwiftDylib1B == [SwiftDylib1B class]);
154 testassert(SwiftDylib1B == SwiftDylib1BClassref);
155 testassert(Dylib1BInits == 1);
156 LOG(%p, SwiftDylib1B);
157
158 Dylib1Test();
159
160 testassert(strcmp([[SwiftDylib1A new] dylib1ACategoryInSameDylib], "dylib1ACategoryInSameDylib") == 0);
161 testassert(strcmp([[SwiftDylib1B new] dylib1BCategoryInSameDylib], "dylib1BCategoryInSameDylib") == 0);
162 testassert(strcmp([[SwiftDylib1A new] dylib1ACategoryInApp], "dylib1ACategoryInApp") == 0);
163 testassert(strcmp([[SwiftDylib1B new] dylib1BCategoryInApp], "dylib1BCategoryInApp") == 0);
164
165 void *handle = dlopen("libswiftMetadataInitializerRealloc-dylib2.dylib", RTLD_LAZY);
166 testassert(handle);
167
168 testassert(strcmp([[SwiftDylib1A new] dylib1ACategoryInOtherDylib], "dylib1ACategoryInOtherDylib") == 0);
169 testassert(strcmp([[SwiftDylib1B new] dylib1BCategoryInOtherDylib], "dylib1BCategoryInOtherDylib") == 0);
170 testassert(strcmp([SwiftDylib1A dylib1ACategoryInAppClassMethod], "dylib1ACategoryInAppClassMethod") == 0);
171 testassert(strcmp([SwiftDylib1B dylib1BCategoryInAppClassMethod], "dylib1BCategoryInAppClassMethod") == 0);
172 [SwiftDylib1A testFromOtherDylib];
173
174 testassert(objc_getClass("RealSwiftSub"));
175 testassert(objc_getClass("RealSwiftDylib1A"));
176 testassert(objc_getClass("RealSwiftDylib1B"));
177
178 succeed(__FILE__);
179 }