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