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