Skip to content

Commit dbd2f82

Browse files
committed
[Runtime] Fix up the heap destroyer in objc_setClassCopyFixupHandler.
We fix up the VWT pointer, but not the heap destroyer. This doesn't matter for classes which use ObjC refcounting, which is the common case for dynamic subclasses, because that doesn't use the heap destroyer pointer. But it does matter for classes that use native Swift refcounting, such as classes that don't inherit from NSObject, or actors. rdar://113657917
1 parent 7ca5998 commit dbd2f82

File tree

3 files changed

+35
-10
lines changed

3 files changed

+35
-10
lines changed

include/swift/ABI/Metadata.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ struct HeapObject;
8181
class WeakReference;
8282
struct UnownedReference;
8383

84+
using HeapObjectDestroyer =
85+
SWIFT_CC(swift) void(SWIFT_CONTEXT HeapObject *);
86+
8487
/// The result of requesting type metadata. Generally the return value of
8588
/// a function.
8689
///
@@ -514,9 +517,6 @@ struct TargetOpaqueMetadata {
514517
TargetMetadata<Runtime> base;
515518
};
516519

517-
using HeapObjectDestroyer =
518-
SWIFT_CC(swift) void(SWIFT_CONTEXT HeapObject *);
519-
520520
/// The prefix on a heap metadata.
521521
template <typename Runtime>
522522
struct TargetHeapMetadataHeaderPrefix {
@@ -561,6 +561,14 @@ struct TargetHeapMetadata : TargetMetadata<Runtime> {
561561
: TargetMetadata<Runtime>(kind) {}
562562
constexpr TargetHeapMetadata(TargetAnyClassMetadataObjCInterop<Runtime> *isa)
563563
: TargetMetadata<Runtime>(isa) {}
564+
565+
HeapObjectDestroyer *getHeapObjectDestroyer() const {
566+
return asFullMetadata(this)->destroy;
567+
}
568+
569+
void setHeapObjectDestroyer(HeapObjectDestroyer *destroy) {
570+
asFullMetadata(this)->destroy = destroy;
571+
}
564572
};
565573
using HeapMetadata = TargetHeapMetadata<InProcess>;
566574

stdlib/public/runtime/Metadata.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,9 +510,11 @@ static void swift_objc_classCopyFixupHandler(Class oldClass, Class newClass) {
510510
if (!oldClassMetadata->isTypeMetadata())
511511
return;
512512

513-
// Copy the value witness table pointer for pointer authentication.
513+
// Copy the value witness table and pointer and heap object destroyer for
514+
// pointer authentication.
514515
auto newClassMetadata = reinterpret_cast<ClassMetadata *>(newClass);
515516
newClassMetadata->setValueWitnesses(oldClassMetadata->getValueWitnesses());
517+
newClassMetadata->setHeapObjectDestroyer(oldClassMetadata->getHeapObjectDestroyer());
516518

517519
// Otherwise, re-sign v-table entries using the extra discriminators stored
518520
// in the v-table descriptor.

test/Interpreter/SDK/dynamic_subclass.swift

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,37 @@
66
import Foundation
77
import ObjectiveC
88

9-
func DoSwizzle(_ c: AnyClass) -> AnyClass {
9+
func DoSwizzle<T: AnyObject>(_ c: T.Type) -> T.Type {
1010
let name = String(utf8String: class_getName(c))!
1111
let subclass: AnyClass = objc_allocateClassPair(c, "\(name)Subclass", 0)!
1212
objc_registerClassPair(subclass);
1313
let subclassSubclass: AnyClass = objc_allocateClassPair(subclass, "\(name)SubclassSubclass", 0)!
1414
objc_registerClassPair(subclassSubclass);
15-
return subclassSubclass
16-
}
17-
18-
class MySwiftClassToBeSwizzled: NSObject {
15+
return subclassSubclass as! T.Type
1916
}
2017

2118
_ = DoSwizzle(NSArray.self)
2219
print("Swizzled NSArray")
2320
// CHECK: Swizzled NSArray
2421

25-
_ = DoSwizzle(MySwiftClassToBeSwizzled.self)
22+
// Ensure that we can dynamically subclass, instantiate, and destroy Swift
23+
// classes, both NSObject-inheriting and native Swift.
24+
class MySwiftClassToBeSwizzled {
25+
required init() {}
26+
}
27+
28+
let swiftSubclass = DoSwizzle(MySwiftClassToBeSwizzled.self)
2629
print("Swizzled MySwiftClassToBeSwizzled")
2730
// CHECK: Swizzled MySwiftClassToBeSwizzled
31+
print("Instantiated the subclass: \(swiftSubclass.init())")
32+
// CHECK: Instantiated the subclass:
33+
34+
class MyNSObjectSwiftClassToBeSwizzled: NSObject {
35+
required override init() {}
36+
}
37+
38+
let swiftNSObjectSubclass = DoSwizzle(MyNSObjectSwiftClassToBeSwizzled.self)
39+
print("Swizzled MyNSObjectSwiftClassToBeSwizzled")
40+
// CHECK: Swizzled MyNSObjectSwiftClassToBeSwizzled
41+
print("Instantiated the subclass: \(swiftNSObjectSubclass.init())")
42+
// CHECK: Instantiated the subclass:

0 commit comments

Comments
 (0)