]> git.saurik.com Git - apple/dyld.git/blob - testing/test-cases/_dyld_for_each_objc_protocol.dtest/main.m
dyld-851.27.tar.gz
[apple/dyld.git] / testing / test-cases / _dyld_for_each_objc_protocol.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_protocol.exe $BUILD_DIR/liblinked1.dylib $BUILD_DIR/liblinked2.dylib -lobjc
5
6 // RUN: ./_dyld_for_each_objc_protocol.exe
7
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.
12
13 #include <mach-o/dyld_priv.h>
14 #include <objc/runtime.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <dlfcn.h>
19
20 #include "test_support.h"
21
22 static bool objcOptimizedByDyld() {
23 extern const uint32_t objcInfo[] __asm("section$start$__DATA_CONST$__objc_imageinfo");
24 return (objcInfo[1] & 0x80);
25 }
26
27 static bool haveDyldCache() {
28 size_t unusedCacheLen;
29 return (_dyld_get_shared_cache_range(&unusedCacheLen) != NULL);
30 }
31
32 // All the libraries have a copy of DyldProtocol
33 @protocol DyldProtocol
34 @end
35
36 // Only the main executable has DyldMainProtocol
37 @protocol DyldMainProtocol
38 @end
39
40 __attribute__((used))
41 static void* useDyldProtocol() {
42 return (void*)@protocol(DyldProtocol);
43 }
44
45 __attribute__((used))
46 static void* useDyldMainProtocol() {
47 return (void*)@protocol(DyldMainProtocol);
48 }
49
50 extern id objc_getProtocol(const char *name);
51
52 static bool gotDyldProtocolMain = false;
53 static bool gotDyldProtocolLinked = false;
54 static bool gotDyldProtocolLinked2 = false;
55
56 static bool isInImage(void* ptr, const char* name) {
57 Dl_info info;
58 if ( dladdr(ptr, &info) == 0 ) {
59 FAIL("dladdr(protocol, xx) failed");
60 return false;
61 }
62 return strstr(info.dli_fname, name) != NULL;
63 }
64
65 int main(int argc, const char* argv[], const char* envp[], const char* apple[]) {
66 if (!objcOptimizedByDyld() || !haveDyldCache()) {
67 __block bool sawClass = false;
68 _dyld_for_each_objc_class("DyldClass", ^(void* classPtr, bool isLoaded, bool* stop) {
69 sawClass = true;
70 });
71 if (sawClass) {
72 FAIL("dyld2 shouldn't see any classes");
73 }
74 PASS("no shared cache or no dyld optimized objc");
75 }
76
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 FAIL("DyldProtocol should have come from liblinked2");
81 }
82
83 // Check that DyldLinkedProtocol comes from liblinked2 as it is last in load order
84 id runtimeDyldLinkedProtocol = objc_getProtocol("DyldLinkedProtocol");
85 if (!isInImage(runtimeDyldLinkedProtocol, "liblinked2")) {
86 FAIL("DyldLinkedProtocol should have come from liblinked2");
87 }
88
89 // Walk all the implementations of "DyldProtocol"
90 _dyld_for_each_objc_protocol("DyldProtocol", ^(void* protocolPtr, bool isLoaded, bool* stop) {
91 // We should walk these in the order liblinked2, liblinked, main exe
92 if (!gotDyldProtocolLinked2) {
93 if (!isInImage(protocolPtr, "liblinked2")) {
94 FAIL("Optimized DyldProtocol should have come from liblinked2");
95 }
96 if (!isLoaded) {
97 FAIL("Optimized DyldProtocol isLoaded should have been set on liblinked2");
98 }
99 gotDyldProtocolLinked2 = true;
100 return;
101 }
102 if (!gotDyldProtocolLinked) {
103 if (!isInImage(protocolPtr, "liblinked1")) {
104 FAIL("Optimized DyldProtocol should have come from liblinked");
105 }
106 if (!isLoaded) {
107 FAIL("Optimized DyldProtocol isLoaded should have been set on liblinked");
108 }
109 gotDyldProtocolLinked = true;
110 return;
111 }
112 if (!gotDyldProtocolMain) {
113 if (!isInImage(protocolPtr, "_dyld_for_each_objc_protocol.exe")) {
114 FAIL("Optimized DyldProtocol should have come from main exe");
115 }
116 if (!isLoaded) {
117 FAIL("Optimized DyldProtocol isLoaded should have been set on main exe");
118 }
119 gotDyldProtocolMain = true;
120 return;
121 }
122 FAIL("Unexpected Optimized DyldProtocol");
123 return;
124 });
125
126 // Visit again, and return liblinked2's DyldProtocol
127 __block void* DyldProtocolImpl = nil;
128 _dyld_for_each_objc_protocol("DyldProtocol", ^(void* protocolPtr, bool isLoaded, bool* stop) {
129 DyldProtocolImpl = protocolPtr;
130 *stop = true;
131 });
132 if (!isInImage(DyldProtocolImpl, "liblinked2")) {
133 FAIL("_dyld_for_each_objc_protocol should have returned DyldProtocol from liblinked2");
134 }
135
136 // Visit DyldMainProtocol and make sure it makes the callback for just the result from main.exe
137 __block void* DyldMainProtocolImpl = nil;
138 _dyld_for_each_objc_protocol("DyldMainProtocol", ^(void* protocolPtr, bool isLoaded, bool* stop) {
139 DyldMainProtocolImpl = protocolPtr;
140 *stop = true;
141 });
142 if (!isInImage(DyldMainProtocolImpl, "_dyld_for_each_objc_protocol.exe")) {
143 FAIL("_dyld_for_each_objc_protocol should have returned DyldMainProtocol from main.exe");
144 }
145
146 #if __has_feature(ptrauth_calls)
147 // Check the ISA was signed correctly on arm64e
148 id dyldMainProtocol = @protocol(DyldMainProtocol);
149 void* originalISA = *(void **)dyldMainProtocol;
150 void* strippedISA = __builtin_ptrauth_strip(originalISA, ptrauth_key_asda);
151 uint64_t discriminator = __builtin_ptrauth_blend_discriminator((void*)dyldMainProtocol, 27361);
152 void* signedISA = __builtin_ptrauth_sign_unauthenticated((void*)strippedISA, 2, discriminator);
153 if ( originalISA != signedISA ) {
154 FAIL("_dyld_for_each_objc_protocol DyldMainProtocol ISA is not signed correctly: %p vs %p",
155 originalISA, signedISA);
156 }
157 #endif
158
159 PASS("Success");
160 }