]> git.saurik.com Git - apple/dyld.git/blob - testing/test-cases/_dyld_for_each_objc_class-missing-weak.dtest/main.mm
ce4b38e9c39a6aa86dc904262f00db6b3209cf27
[apple/dyld.git] / testing / test-cases / _dyld_for_each_objc_class-missing-weak.dtest / main.mm
1
2 // BUILD: $CC missing.m -dynamiclib -o $TEMP_DIR/libmissing.dylib -install_name $BUILD_DIR/libmissing.dylib -lobjc
3 // BUILD: $CC lib1.m -dynamiclib -o $BUILD_DIR/liblinked1.dylib -install_name $RUN_DIR/liblinked1.dylib -lobjc
4 // BUILD: $CC lib2.m -dynamiclib -o $BUILD_DIR/liblinked2.dylib -install_name $RUN_DIR/liblinked2.dylib -lobjc $TEMP_DIR/libmissing.dylib
5 // BUILD: $CC main.mm -o $BUILD_DIR/_dyld_for_each_objc_class-missing-weak.exe -lobjc $BUILD_DIR/liblinked1.dylib $BUILD_DIR/liblinked2.dylib $TEMP_DIR/libmissing.dylib -lc++
6
7 // RUN: ./_dyld_for_each_objc_class-missing-weak.exe
8
9 // liblinked2 weakly links libmissing and so has a missing weak superclass.
10 // This means we should not see classes from liblinked be returned from _dyld_for_each_objc_class
11 // liblinked1 itself has classes which are fine so shoud be in the map.
12 // At runtime, objc is going to walk the images in reverse load order so will see the classes in liblinked2 first
13 // which are the ones we couldn't optimize. But objc should then check the closure class map and choose the class
14 // from liblinked
15
16 #include <mach-o/dyld_priv.h>
17
18 #import <Foundation/Foundation.h>
19
20 // All the libraries have a copy of DyldClass
21 @interface DyldClass : NSObject
22 @end
23
24 @implementation DyldClass
25 @end
26
27 // Only the main executable has DyldMainClass
28 @interface DyldMainClass : NSObject
29 @end
30
31 @implementation DyldMainClass
32 @end
33
34 extern Class OBJC_CLASS_$_DyldClass;
35 extern Class OBJC_CLASS_$_DyldMainClass;
36
37 Class getMainDyldClass() {
38 return (Class)&OBJC_CLASS_$_DyldClass;
39 }
40
41 Class getMainDyldMainClass() {
42 return (Class)&OBJC_CLASS_$_DyldMainClass;
43 }
44
45 extern "C" int printf(const char*, ...);
46
47 extern "C" id objc_getClass(const char *name);
48
49 // Get the DyldClass from liblinked1.dylib
50 extern "C" id getLinked1DyldClass();
51
52 // Get the DyldLinkedClass from liblinked1.dylib
53 extern "C" id getLinked1DyldLinkedClass();
54
55 // Get the DyldLinkedClass from liblinked.dylib
56 extern "C" id getLinked2DyldLinkedClass();
57
58 // Get the DyldClass from libmissing.dylib
59 // Note, this is weak_import and missing so this must fail
60 __attribute__((weak_import))
61 extern "C" id getMissingDyldClass();
62
63 static bool gotDyldClassMain = false;
64 static bool gotDyldClassLinked1 = false;
65
66 int main() {
67 printf("[BEGIN] _dyld_for_each_objc_class-missing-weak\n");
68
69 // This API is only available with dyld3 and shared caches. If we have dyld2 then don't do anything
70 const char* testDyldMode = getenv("TEST_DYLD_MODE");
71 assert(testDyldMode);
72
73 size_t unusedCacheLen;
74 bool haveSharedCache = _dyld_get_shared_cache_range(&unusedCacheLen) != 0;
75 if (!strcmp(testDyldMode, "2") || !haveSharedCache) {
76 __block bool sawClass = false;
77 _dyld_for_each_objc_class("DyldClass", ^(void* classPtr, bool isLoaded, bool* stop) {
78 sawClass = true;
79 });
80 if (sawClass) {
81 printf("[FAIL] _dyld_for_each_objc_class: dyld2 shouldn't see any classes\n");
82 return 0;
83 }
84 printf("[PASS] _dyld_for_each_objc_class (dyld2 or no shared cache)\n");
85 return 0;
86 }
87
88 // Make sure libmissing.dylib is actually missing
89 if (&getMissingDyldClass != nil) {
90 printf("[FAIL] _dyld_for_each_objc_class-missing-weak: libmissing needs to be missing\n");
91 return 0;
92 }
93
94 // DyldClass in liblinked1 should exist as its superclass is just NSObject
95 if (getLinked1DyldClass() == nil) {
96 printf("[FAIL] _dyld_for_each_objc_class-missing-weak: liblinked1 DyldClass should exist\n");
97 return 0;
98 }
99
100 // DyldLinkedClass in liblinked1 should exist as its superclass is just NSObject
101 if (getLinked1DyldLinkedClass() == nil) {
102 printf("[FAIL] _dyld_for_each_objc_class-missing-weak: liblinked1 DyldLinkedClass should exist\n");
103 return 0;
104 }
105
106 // DyldLinkedClass in liblinked2 should exist as its superclass is just NSObject
107 if (getLinked2DyldLinkedClass() == nil) {
108 printf("[FAIL] _dyld_for_each_objc_class-missing-weak: liblinked2 DyldLinkedClass should exist\n");
109 return 0;
110 }
111
112 // Check that DyldMainClass comes main.exe as that is its only definition
113 id runtimeDyldMainClass = objc_getClass("DyldMainClass");
114 if (runtimeDyldMainClass != getMainDyldMainClass()) {
115 printf("[FAIL] _dyld_for_each_objc_class-missing-weak: DyldMainClass should have come from main.exe\n");
116 return 0;
117 }
118
119 // Check that DyldClass comes liblinked1 as it should be missing from liblinked2
120 id runtimeDyldClass = objc_getClass("DyldClass");
121 if (runtimeDyldClass != getLinked1DyldClass()) {
122 printf("[FAIL] _dyld_for_each_objc_class-missing-weak: DyldClass should have come from liblinked1\n");
123 return 0;
124 }
125
126 // Check that DyldLinkedClass comes from liblinked2
127 // Note, this changes once the objc runtime has adopted our changes. Don't test it for now
128 #if 0
129 id runtimeDyldLinkedClass = objc_getClass("DyldLinkedClass");
130 if (runtimeDyldLinkedClass != getLinked2DyldLinkedClass()) {
131 printf("[FAIL] _dyld_for_each_objc_class-missing-weak: DyldLinkedClass should have come from liblinked2\n");
132 return 0;
133 }
134 #endif
135
136 _dyld_for_each_objc_class("DyldClass", ^(void* classPtr, bool isLoaded, bool* stop) {
137 // We should walk these in the order liblinked, main exe
138 if (!gotDyldClassLinked1) {
139 if (classPtr != getLinked1DyldClass()) {
140 printf("[FAIL] _dyld_for_each_objc_class-missing-weak: DyldClass should have come from liblinked1\n");
141 *stop = true;
142 return;
143 }
144 if (!isLoaded) {
145 printf("[FAIL] _dyld_for_each_objc_class-missing-weak: DyldClass isLoaded should have been set on liblinked1\n");
146 *stop = true;
147 return;
148 }
149 gotDyldClassLinked1 = true;
150 return;
151 }
152 if (!gotDyldClassMain) {
153 if (classPtr != getMainDyldClass()) {
154 printf("[FAIL] _dyld_for_each_objc_class-missing-weak: DyldClass should have come from main exe\n");
155 *stop = true;
156 return;
157 }
158 if (!isLoaded) {
159 printf("[FAIL] _dyld_for_each_objc_class-missing-weak: DyldClass isLoaded should have been set on main exe\n");
160 *stop = true;
161 return;
162 }
163 gotDyldClassMain = true;
164 return;
165 }
166 printf("[FAIL] _dyld_for_each_objc_class-missing-weak: Unexpected DyldClass\n");
167 return;
168 });
169
170 if (!gotDyldClassLinked1) {
171 printf("[FAIL] _dyld_for_each_objc_class-missing-weak: _dyld_for_each_objc_class should have seen DyldClass in liblinked1\n");
172 return 0;
173 }
174
175 if (!gotDyldClassMain) {
176 printf("[FAIL] _dyld_for_each_objc_class-missing-weak: _dyld_for_each_objc_class should have seen DyldClass in main.exe\n");
177 return 0;
178 }
179
180 // Visit again, and return liblinked1's DyldClass
181 // Visit again, and return liblinked2's DyldClass
182 __block void* dyldClassImpl = nil;
183 _dyld_for_each_objc_class("DyldClass", ^(void* classPtr, bool isLoaded, bool* stop) {
184 dyldClassImpl = classPtr;
185 *stop = true;
186 });
187 if (dyldClassImpl != getLinked1DyldClass()) {
188 printf("[FAIL] _dyld_for_each_objc_class-missing-weak: _dyld_for_each_objc_class should have returned DyldClass from liblinked1\n");
189 return 0;
190 }
191
192 // Visit again, and return liblinked1's DyldClass
193 dyldClassImpl = nil;
194 _dyld_for_each_objc_class("DyldClass", ^(void* classPtr, bool isLoaded, bool* stop) {
195 // We should walk these in the order liblinked, main exe
196 // And return the one from main.exe
197 if (classPtr == getLinked1DyldClass())
198 return;
199 dyldClassImpl = classPtr;
200 *stop = true;
201 });
202 if (dyldClassImpl != getMainDyldClass()) {
203 printf("[FAIL] _dyld_for_each_objc_class-missing-weak: _dyld_for_each_objc_class should have returned DyldClass from main.exe\n");
204 return 0;
205 }
206
207 printf("[PASS] _dyld_for_each_objc_class-missing-weak\n");
208
209 return 0;
210 }