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