2020#include " Overrides.h"
2121#include " ../../public/runtime/Private.h"
2222#include " swift/Basic/Lazy.h"
23+ #include < mach-o/dyld.h>
24+ #include < mach-o/getsect.h>
2325#include < objc/runtime.h>
2426
2527using namespace swift ;
2628
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+
2739// Clone of private function getRootSuperclass. This returns the SwiftObject
2840// class in the ABI-stable dylib, regardless of what the local runtime build
2941// does, since we're always patching an ABI-stable dylib.
@@ -33,6 +45,50 @@ const ClassMetadata *swift::getRootSuperclass() {
3345 return (const ClassMetadata *)theClass;
3446}
3547
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+
3692// Clone of private helper swift::_swiftoverride_class_getSuperclass
3793// for use in the override implementation.
3894static const Metadata *_swift50override_class_getSuperclass (
@@ -56,6 +112,10 @@ swift::swift50override_conformsToProtocol(const Metadata *type,
56112 const ProtocolDescriptor *protocol,
57113 ConformsToProtocol_t *original_conformsToProtocol)
58114{
115+ // Register our add image callback if necessary.
116+ static OnceToken_t token;
117+ SWIFT_ONCE_F (token, registerAddImageCallback, nullptr );
118+
59119 // The implementation of swift_conformsToProtocol in Swift 5.0 would return
60120 // a false negative answer when asking whether a subclass conforms using
61121 // a conformance from a superclass. Work around this by walking up the
0 commit comments