20
20
#include " Overrides.h"
21
21
#include " ../../public/runtime/Private.h"
22
22
#include " swift/Basic/Lazy.h"
23
+ #include < mach-o/dyld.h>
24
+ #include < mach-o/getsect.h>
23
25
#include < objc/runtime.h>
24
26
25
27
using namespace swift ;
26
28
29
+ #if __POINTER_WIDTH__ == 64
30
+ using mach_header_platform = mach_header_64;
31
+ #else
32
+ using mach_header_platform = mach_header;
33
+ #endif
34
+
35
+ // / The Mach-O section name for the section containing protocol conformances.
36
+ // / This lives within SEG_TEXT.
37
+ constexpr const char ProtocolConformancesSection[] = " __swift5_proto" ;
38
+
27
39
// Clone of private function getRootSuperclass. This returns the SwiftObject
28
40
// class in the ABI-stable dylib, regardless of what the local runtime build
29
41
// does, since we're always patching an ABI-stable dylib.
@@ -33,6 +45,50 @@ const ClassMetadata *swift::getRootSuperclass() {
33
45
return (const ClassMetadata *)theClass;
34
46
}
35
47
48
+ // A dummy target context descriptor to use in conformance records which point
49
+ // to a NULL descriptor. It doesn't have to be completely valid, just something
50
+ // that code reading conformance descriptors will ignore.
51
+ struct {
52
+ ContextDescriptorFlags flags;
53
+ int32_t offset;
54
+ } DummyTargetContextDescriptor = {
55
+ ContextDescriptorFlags ().withKind (ContextDescriptorKind::Extension),
56
+ 0
57
+ };
58
+
59
+ // Search for any protocol conformance descriptors with a NULL type descriptor
60
+ // and rewrite those to point to the dummy descriptor. This occurs when an
61
+ // extension is used to declare a conformance on a weakly linked type and that
62
+ // type is not present at runtime.
63
+ static void addImageCallback (const mach_header *mh, intptr_t vmaddr_slide) {
64
+ unsigned long size;
65
+ const uint8_t *section =
66
+ getsectiondata (reinterpret_cast <const mach_header_platform *>(mh),
67
+ SEG_TEXT, ProtocolConformancesSection,
68
+ &size);
69
+ if (!section)
70
+ return ;
71
+
72
+ auto recordsBegin
73
+ = reinterpret_cast <const ProtocolConformanceRecord*>(section);
74
+ auto recordsEnd
75
+ = reinterpret_cast <const ProtocolConformanceRecord*>
76
+ (section + size);
77
+ for (auto record = recordsBegin; record != recordsEnd; record++) {
78
+ auto descriptor = record->get ();
79
+ if (auto typePtr = descriptor->_getTypeDescriptorLocation ()) {
80
+ if (*typePtr == nullptr )
81
+ *typePtr = reinterpret_cast <TargetContextDescriptor<InProcess> *>(
82
+ &DummyTargetContextDescriptor);
83
+ }
84
+ }
85
+ }
86
+
87
+ // Register the add image callback with dyld.
88
+ static void registerAddImageCallback (void *) {
89
+ _dyld_register_func_for_add_image (addImageCallback);
90
+ }
91
+
36
92
// Clone of private helper swift::_swiftoverride_class_getSuperclass
37
93
// for use in the override implementation.
38
94
static const Metadata *_swift50override_class_getSuperclass (
@@ -56,6 +112,10 @@ swift::swift50override_conformsToProtocol(const Metadata *type,
56
112
const ProtocolDescriptor *protocol,
57
113
ConformsToProtocol_t *original_conformsToProtocol)
58
114
{
115
+ // Register our add image callback if necessary.
116
+ static OnceToken_t token;
117
+ SWIFT_ONCE_F (token, registerAddImageCallback, nullptr );
118
+
59
119
// The implementation of swift_conformsToProtocol in Swift 5.0 would return
60
120
// a false negative answer when asking whether a subclass conforms using
61
121
// a conformance from a superclass. Work around this by walking up the
0 commit comments