]> git.saurik.com Git - apple/dyld.git/blob - testing/test-cases/_dyld_for_each_objc_class-missing-weak.dtest/main.mm
dyld-750.6.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 $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 $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 // All the libraries have a copy of DyldClass
25 @interface DyldClass : NSObject
26 @end
27
28 @implementation DyldClass
29 @end
30
31 // Only the main executable has DyldMainClass
32 @interface DyldMainClass : NSObject
33 @end
34
35 @implementation DyldMainClass
36 @end
37
38 extern Class OBJC_CLASS_$_DyldClass;
39 extern Class OBJC_CLASS_$_DyldMainClass;
40
41 Class getMainDyldClass() {
42 return (Class)&OBJC_CLASS_$_DyldClass;
43 }
44
45 Class getMainDyldMainClass() {
46 return (Class)&OBJC_CLASS_$_DyldMainClass;
47 }
48
49 extern "C" id objc_getClass(const char *name);
50
51 // Get the DyldClass from liblinked1.dylib
52 extern "C" id getLinked1DyldClass();
53
54 // Get the DyldLinkedClass from liblinked1.dylib
55 extern "C" id getLinked1DyldLinkedClass();
56
57 // Get the DyldLinkedClass from liblinked.dylib
58 extern "C" id getLinked2DyldLinkedClass();
59
60 // Get the DyldClass from libmissing.dylib
61 // Note, this is weak_import and missing so this must fail
62 __attribute__((weak_import))
63 extern "C" id getMissingDyldClass();
64
65 static bool gotDyldClassMain = false;
66 static bool gotDyldClassLinked1 = false;
67
68 int main(int argc, const char* argv[], const char* envp[], const char* apple[]) {
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 FAIL("dyld2 shouldn't see any classes");
82 }
83 PASS("dyld2 or no shared cache");
84 }
85
86 // Make sure libmissing.dylib is actually missing
87 if (&getMissingDyldClass != nil) {
88 FAIL("libmissing needs to be missing");
89 }
90
91 // DyldClass in liblinked1 should exist as its superclass is just NSObject
92 if (getLinked1DyldClass() == nil) {
93 FAIL("liblinked1 DyldClass should exist");
94 }
95
96 // DyldLinkedClass in liblinked1 should exist as its superclass is just NSObject
97 if (getLinked1DyldLinkedClass() == nil) {
98 FAIL("liblinked1 DyldLinkedClass should exist");
99 }
100
101 // DyldLinkedClass in liblinked2 should exist as its superclass is just NSObject
102 if (getLinked2DyldLinkedClass() == nil) {
103 FAIL("liblinked2 DyldLinkedClass should exist");
104 }
105
106 // Check that DyldMainClass comes main.exe as that is its only definition
107 id runtimeDyldMainClass = objc_getClass("DyldMainClass");
108 if (runtimeDyldMainClass != getMainDyldMainClass()) {
109 FAIL("DyldMainClass should have come from main.exe");
110 }
111
112 // Check that DyldClass comes liblinked1 as it should be missing from liblinked2
113 id runtimeDyldClass = objc_getClass("DyldClass");
114 if (runtimeDyldClass != getLinked1DyldClass()) {
115 FAIL("DyldClass should have come from liblinked1");
116 }
117
118 // Check that DyldLinkedClass comes from liblinked2
119 // Note, this changes once the objc runtime has adopted our changes. Don't test it for now
120 #if 0
121 id runtimeDyldLinkedClass = objc_getClass("DyldLinkedClass");
122 if (runtimeDyldLinkedClass != getLinked2DyldLinkedClass()) {
123 FAIL("DyldLinkedClass should have come from liblinked2");
124 }
125 #endif
126
127 _dyld_for_each_objc_class("DyldClass", ^(void* classPtr, bool isLoaded, bool* stop) {
128 // We should walk these in the order liblinked, main exe
129 if (!gotDyldClassLinked1) {
130 if (classPtr != getLinked1DyldClass()) {
131 FAIL("DyldClass should have come from liblinked1");
132 }
133 if (!isLoaded) {
134 FAIL("DyldClass isLoaded should have been set on liblinked1");
135 }
136 gotDyldClassLinked1 = true;
137 return;
138 }
139 if (!gotDyldClassMain) {
140 if (classPtr != getMainDyldClass()) {
141 FAIL("DyldClass should have come from main exe");
142 }
143 if (!isLoaded) {
144 FAIL("DyldClass isLoaded should have been set on main exe");
145 }
146 gotDyldClassMain = true;
147 return;
148 }
149 FAIL("Unexpected DyldClass");
150 });
151
152 if (!gotDyldClassLinked1) {
153 FAIL("_dyld_for_each_objc_class should have seen DyldClass in liblinked1");
154 }
155
156 if (!gotDyldClassMain) {
157 FAIL("_dyld_for_each_objc_class should have seen DyldClass in main.exe");
158 }
159
160 // Visit again, and return liblinked1's DyldClass
161 // Visit again, and return liblinked2's DyldClass
162 __block void* dyldClassImpl = nil;
163 _dyld_for_each_objc_class("DyldClass", ^(void* classPtr, bool isLoaded, bool* stop) {
164 dyldClassImpl = classPtr;
165 *stop = true;
166 });
167 if (dyldClassImpl != getLinked1DyldClass()) {
168 FAIL("_dyld_for_each_objc_class should have returned DyldClass from liblinked1");
169 }
170
171 // Visit again, and return liblinked1's DyldClass
172 dyldClassImpl = nil;
173 _dyld_for_each_objc_class("DyldClass", ^(void* classPtr, bool isLoaded, bool* stop) {
174 // We should walk these in the order liblinked, main exe
175 // And return the one from main.exe
176 if (classPtr == getLinked1DyldClass())
177 return;
178 dyldClassImpl = classPtr;
179 *stop = true;
180 });
181 if (dyldClassImpl != getMainDyldClass()) {
182 FAIL("_dyld_for_each_objc_class should have returned DyldClass from main.exe");
183 }
184
185 PASS("SUCCESS");
186 }