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