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_protocol.exe $BUILD_DIR/liblinked1.dylib $BUILD_DIR/liblinked2.dylib -lobjc
6 // RUN: ./_dyld_for_each_objc_protocol.exe
8 // The preoptimized objc protocol information is available via _dyld_for_each_objc_protocol().
9 // This test ensures that we match the objc behaviour when there are duplicates.
10 // For objc today, it walks the images in reverse load order, so the deepest library will be
11 // the canonical definition of a protocol.
13 #include <mach-o/dyld_priv.h>
14 #include <objc/runtime.h>
20 // All the libraries have a copy of DyldProtocol
21 @protocol DyldProtocol
24 // Only the main executable has DyldMainProtocol
25 @protocol DyldMainProtocol
29 static void* useDyldProtocol() {
30 return (void*)@protocol(DyldProtocol);
34 static void* useDyldMainProtocol() {
35 return (void*)@protocol(DyldMainProtocol);
38 extern int printf(const char*, ...);
40 extern id objc_getProtocol(const char *name);
42 static bool gotDyldProtocolMain = false;
43 static bool gotDyldProtocolLinked = false;
44 static bool gotDyldProtocolLinked2 = false;
46 static bool isInImage(void* ptr, const char* name) {
48 if ( dladdr(ptr, &info) == 0 ) {
49 printf("[FAIL] _dyld_for_each_objc_protocol dladdr(protocol, xx) failed\n");
52 return strstr(info.dli_fname, name) != NULL;
56 printf("[BEGIN] _dyld_for_each_objc_protocol\n");
58 // This API is only available with dyld3 and shared caches. If we have dyld2 then don't do anything
59 const char* testDyldMode = getenv("TEST_DYLD_MODE");
62 size_t unusedCacheLen;
63 bool haveSharedCache = _dyld_get_shared_cache_range(&unusedCacheLen) != 0;
64 if (!strcmp(testDyldMode, "2") || !haveSharedCache) {
65 __block bool sawProtocol = false;
66 _dyld_for_each_objc_protocol("DyldProtocol", ^(void* protocolPtr, bool isLoaded, bool* stop) {
70 printf("[FAIL] _dyld_for_each_objc_protocol: dyld2 shouldn't see any protocols\n");
73 printf("[PASS] _dyld_for_each_objc_protocol (dyld2 or no shared cache)\n");
77 // Check that DyldProtocol comes from liblinked2 as it is last in load order
78 id runtimeDyldProtocol = objc_getProtocol("DyldProtocol");
79 if (!isInImage(runtimeDyldProtocol, "liblinked2")) {
80 printf("[FAIL] _dyld_for_each_objc_protocol: DyldProtocol should have come from liblinked2\n");
84 // Check that DyldLinkedProtocol comes from liblinked2 as it is last in load order
85 id runtimeDyldLinkedProtocol = objc_getProtocol("DyldLinkedProtocol");
86 if (!isInImage(runtimeDyldLinkedProtocol, "liblinked2")) {
87 printf("[FAIL] _dyld_for_each_objc_protocol: DyldLinkedProtocol should have come from liblinked2\n");
91 // Walk all the implementations of "DyldProtocol"
92 _dyld_for_each_objc_protocol("DyldProtocol", ^(void* protocolPtr, bool isLoaded, bool* stop) {
93 // We should walk these in the order liblinked2, liblinked, main exe
94 if (!gotDyldProtocolLinked2) {
95 if (!isInImage(protocolPtr, "liblinked2")) {
96 printf("[FAIL] _dyld_for_each_objc_protocol: Optimized DyldProtocol should have come from liblinked2\n");
101 printf("[FAIL] _dyld_for_each_objc_protocol: Optimized DyldProtocol isLoaded should have been set on liblinked2\n");
105 gotDyldProtocolLinked2 = true;
108 if (!gotDyldProtocolLinked) {
109 if (!isInImage(protocolPtr, "liblinked1")) {
110 printf("[FAIL] _dyld_for_each_objc_protocol: Optimized DyldProtocol should have come from liblinked\n");
115 printf("[FAIL] _dyld_for_each_objc_protocol: Optimized DyldProtocol isLoaded should have been set on liblinked\n");
119 gotDyldProtocolLinked = true;
122 if (!gotDyldProtocolMain) {
123 if (!isInImage(protocolPtr, "_dyld_for_each_objc_protocol.exe")) {
124 printf("[FAIL] _dyld_for_each_objc_protocol: Optimized DyldProtocol should have come from main exe\n");
129 printf("[FAIL] _dyld_for_each_objc_protocol: Optimized DyldProtocol isLoaded should have been set on main exe\n");
133 gotDyldProtocolMain = true;
136 printf("[FAIL] _dyld_for_each_objc_protocol: Unexpected Optimized DyldProtocol\n");
140 // Visit again, and return liblinked2's DyldProtocol
141 __block void* DyldProtocolImpl = nil;
142 _dyld_for_each_objc_protocol("DyldProtocol", ^(void* protocolPtr, bool isLoaded, bool* stop) {
143 DyldProtocolImpl = protocolPtr;
146 if (!isInImage(DyldProtocolImpl, "liblinked2")) {
147 printf("[FAIL] _dyld_for_each_objc_protocol: _dyld_for_each_objc_protocol should have returned DyldProtocol from liblinked2\n");
151 // Visit DyldMainProtocol and make sure it makes the callback for just the result from main.exe
152 __block void* DyldMainProtocolImpl = nil;
153 _dyld_for_each_objc_protocol("DyldMainProtocol", ^(void* protocolPtr, bool isLoaded, bool* stop) {
154 DyldMainProtocolImpl = protocolPtr;
157 if (!isInImage(DyldMainProtocolImpl, "_dyld_for_each_objc_protocol.exe")) {
158 printf("[FAIL] _dyld_for_each_objc_protocol: _dyld_for_each_objc_protocol should have returned DyldMainProtocol from main.exe\n");
162 printf("[PASS] _dyld_for_each_objc_protocol\n");