]> git.saurik.com Git - apple/dyld.git/blob - testing/test-cases/_dyld_for_each_objc_class-duplicates.dtest/main.m
dyld-851.27.tar.gz
[apple/dyld.git] / testing / test-cases / _dyld_for_each_objc_class-duplicates.dtest / main.m
1
2 // BUILD: $CC linked1.m -dynamiclib -o $BUILD_DIR/liblinked1.dylib -install_name $RUN_DIR/liblinked1.dylib -lobjc
3 // BUILD: $CC linked2.m -dynamiclib -o $BUILD_DIR/liblinked2.dylib -install_name $RUN_DIR/liblinked2.dylib -lobjc
4 // BUILD: $CC main.m -o $BUILD_DIR/_dyld_for_each_objc_class-duplicates.exe $BUILD_DIR/liblinked1.dylib $BUILD_DIR/liblinked2.dylib -lobjc -framework Foundation
5
6 // RUN: ./_dyld_for_each_objc_class-duplicates.exe
7
8 #include <mach-o/dyld_priv.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 #import <Foundation/NSObject.h>
13
14 #include "test_support.h"
15
16
17 static bool objcOptimizedByDyld() {
18 extern const uint32_t objcInfo[] __asm("section$start$__DATA_CONST$__objc_imageinfo");
19 return (objcInfo[1] & 0x80);
20 }
21
22 static bool haveDyldCache() {
23 size_t unusedCacheLen;
24 return (_dyld_get_shared_cache_range(&unusedCacheLen) != NULL);
25 }
26
27 // All the libraries have a copy of NSString
28 @interface NSString : NSObject
29 @end
30
31 @implementation NSString
32 @end
33
34 extern Class OBJC_CLASS_$_NSString;
35
36 // The main executable also has versions of these Foundation classes
37 @interface NSDictionary : NSObject
38 @end
39
40 @implementation NSDictionary
41 @end
42
43 extern Class OBJC_CLASS_$_NSDictionary;
44
45 @interface NSError : NSObject
46 @end
47
48 @implementation NSError
49 @end
50
51 extern Class OBJC_CLASS_$_NSError;
52
53 @interface NSSet : NSObject
54 @end
55
56 @implementation NSSet
57 @end
58
59 extern Class OBJC_CLASS_$_NSSet;
60
61 @interface NSArray : NSObject
62 @end
63
64 @implementation NSArray
65 @end
66
67 extern Class OBJC_CLASS_$_NSArray;
68
69 Class getMainNSString() {
70 return (Class)&OBJC_CLASS_$_NSString;
71 }
72
73 extern id objc_getClass(const char *name);
74
75 // Get the NSString from liblinked1.dylib
76 extern Class getLinked1NSString();
77
78 // Get the NSString from liblinked2.dylib
79 extern Class getLinked2NSString();
80
81 static bool gotNSStringMain = false;
82 static bool gotNSStringLinked = false;
83 static bool gotNSStringLinked2 = false;
84 static bool gotNSStringFoundation = false;
85
86 void testDuplicate(const char* className, Class nonCacheClass) {
87 // Walk all the implementations of the class. There should be 2. One in the executable and one in the shared cache
88 // The shared cache one should be returned first.
89
90 // The objc runtime should have chosen the Foundation one as the canonical definition.
91 Class objcRuntimeClassImpl = (Class)objc_getClass(className);
92 if (objcRuntimeClassImpl == nil) {
93 FAIL("class %s not found via runtime", className);
94 }
95
96 if (objcRuntimeClassImpl == nonCacheClass) {
97 FAIL("class %s from runtime should not match main exexutable", className);
98 }
99
100 __block bool foundSharedCacheImpl = false;
101 __block bool foundMainExecutableImpl = false;
102 __block bool foundAnyClass = false;
103 __block bool foundTooManyClasses = false;
104 _dyld_for_each_objc_class(className, ^(void* classPtr, bool isLoaded, bool* stop) {
105 foundAnyClass = true;
106
107 // We should walk these in the order Foundation, main exe
108 if (!foundSharedCacheImpl) {
109 if (classPtr != objcRuntimeClassImpl) {
110 FAIL("Optimized class %s should have come from Foundation", className);
111 }
112 if (!isLoaded) {
113 FAIL("Optimized class %s isLoaded should have been set on Foundation", className);
114 }
115 foundSharedCacheImpl = true;
116 return;
117 }
118 if (!foundMainExecutableImpl) {
119 if (classPtr != nonCacheClass) {
120 FAIL("Optimized class %s should have come from main executable", className);
121 }
122 if (!isLoaded) {
123 FAIL("Optimized class %s isLoaded should have been set on main executable", className);
124 }
125 foundMainExecutableImpl = true;
126 return;
127 }
128
129 foundTooManyClasses = true;
130 FAIL("class %s found somewhere other than main executable and Foundation", className);
131 });
132
133 if (!foundAnyClass) {
134 FAIL("class %s not found", className);
135 }
136
137 if (foundTooManyClasses) {
138 FAIL("class %s found too many times", className);
139 }
140
141 if (!foundSharedCacheImpl || !foundMainExecutableImpl) {
142 FAIL("class %s not found for shared cache or main executable", className);
143 }
144 }
145
146 int main(int argc, const char* argv[], const char* envp[], const char* apple[]) {
147 size_t sharedCacheLen = 0;
148 const void* sharedCacheStart = _dyld_get_shared_cache_range(&sharedCacheLen);
149 if (!objcOptimizedByDyld() || (sharedCacheStart==NULL)) {
150 __block bool sawClass = false;
151 _dyld_for_each_objc_class("DyldClass", ^(void* classPtr, bool isLoaded, bool* stop) {
152 sawClass = true;
153 });
154 if (sawClass) {
155 FAIL("dyld2 shouldn't see any classes");
156 }
157 PASS("no shared cache or no dyld optimized objc");
158 }
159
160 // Check that NSString comes from Foundation as the shared cache should win here.
161 id runtimeNSString = objc_getClass("NSString");
162 if ( (uint64_t)runtimeNSString < (uint64_t)sharedCacheStart ) {
163 FAIL("NSString should have come from Foundation but instead was %p", runtimeNSString);
164 }
165 if ( (uint64_t)runtimeNSString >= ((uint64_t)sharedCacheStart + sharedCacheLen) ) {
166 FAIL("NSString should have come from Foundation but instead was %p", runtimeNSString);
167 }
168
169 // Walk all the implementations of "NSString"
170 _dyld_for_each_objc_class("NSString", ^(void* classPtr, bool isLoaded, bool* stop) {
171 // We should walk these in the order Foundation, liblinked2, liblinked, main exe
172 if (!gotNSStringFoundation) {
173 if (classPtr != runtimeNSString) {
174 FAIL("Optimized NSString should have come from Foundation");
175 }
176 if (!isLoaded) {
177 FAIL("Optimized NSString isLoaded should have been set on Foundation");
178 }
179 gotNSStringFoundation = true;
180 return;
181 }
182 if (!gotNSStringLinked2) {
183 if (classPtr != getLinked2NSString()) {
184 FAIL("Optimized NSString should have come from liblinked2");
185 }
186 if (!isLoaded) {
187 FAIL("Optimized NSString isLoaded should have been set on liblinked2");
188 }
189 gotNSStringLinked2 = true;
190 return;
191 }
192 if (!gotNSStringLinked) {
193 if (classPtr != getLinked1NSString()) {
194 FAIL("Optimized NSString should have come from liblinked");
195 }
196 if (!isLoaded) {
197 FAIL("Optimized NSString isLoaded should have been set on liblinked");
198 }
199 gotNSStringLinked = true;
200 return;
201 }
202 if (!gotNSStringMain) {
203 if (classPtr != getMainNSString()) {
204 FAIL("Optimized NSString should have come from main exe");
205 }
206 if (!isLoaded) {
207 FAIL("Optimized NSString isLoaded should have been set on main exe");
208 }
209 gotNSStringMain = true;
210 return;
211 }
212 FAIL("Unexpected Optimized NSString");
213 });
214
215 if ( !gotNSStringFoundation || !gotNSStringLinked2 || !gotNSStringLinked || !gotNSStringMain) {
216 FAIL("Failed to find all duplicates of 'NSString'");
217 }
218
219 // Visit again, and return Foundation's NSString
220 __block void* NSStringImpl = nil;
221 _dyld_for_each_objc_class("NSString", ^(void* classPtr, bool isLoaded, bool* stop) {
222 NSStringImpl = classPtr;
223 *stop = true;
224 });
225 if (NSStringImpl != runtimeNSString) {
226 FAIL("_dyld_for_each_objc_class should have returned NSString from Foundation");
227 }
228
229 testDuplicate("NSDictionary", (Class)&OBJC_CLASS_$_NSDictionary);
230 testDuplicate("NSError", (Class)&OBJC_CLASS_$_NSError);
231 testDuplicate("NSSet", (Class)&OBJC_CLASS_$_NSSet);
232 testDuplicate("NSArray", (Class)&OBJC_CLASS_$_NSArray);
233
234 PASS("Success");
235 }