Skip to content

Commit 5638402

Browse files
authored
Merge pull request #62 from ddddxxx/fix-objc-derived-class
fix: crash when inspect class that derived from pure objc class
2 parents 3e99509 + bbee4dc commit 5638402

File tree

3 files changed

+44
-10
lines changed

3 files changed

+44
-10
lines changed

Sources/Runtime/Layouts/ClassMetadataLayout.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,22 @@
2222

2323
import Foundation
2424

25+
// Swift class or objc class
26+
struct AnyClassMetadataLayout {
27+
var _kind: Int // isaPointer for classes
28+
var superClass: Any.Type
29+
var objCRuntimeReserve: (Int, Int)
30+
var rodataPointer: Int
31+
32+
var isSwiftClass: Bool {
33+
return (rodataPointer & classIsSwiftMask()) != 0
34+
}
35+
}
36+
2537
struct ClassMetadataLayout: NominalMetadataLayoutType {
2638
var _kind: Int // isaPointer for classes
2739
var superClass: Any.Type
28-
var objCRuntimeReserve1: Int
29-
var objCRuntimeReserve2: Int
40+
var objCRuntimeReserve: (Int, Int)
3041
var rodataPointer: Int
3142
var classFlags: Int32
3243
var instanceAddressPoint: UInt32

Sources/Runtime/Metadata/ClassMetadata.swift

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,23 @@
2222

2323
import Foundation
2424

25+
struct AnyClassMetadata {
26+
27+
var pointer: UnsafeMutablePointer<AnyClassMetadataLayout>
28+
29+
init(type: Any.Type) {
30+
pointer = unsafeBitCast(type, to: UnsafeMutablePointer<AnyClassMetadataLayout>.self)
31+
}
32+
33+
func asClassMetadata() -> ClassMetadata? {
34+
guard pointer.pointee.isSwiftClass else {
35+
return nil
36+
}
37+
let ptr = pointer.raw.assumingMemoryBound(to: ClassMetadataLayout.self)
38+
return ClassMetadata(pointer: ptr)
39+
}
40+
}
41+
2542
struct ClassMetadata: NominalMetadataType {
2643

2744
var pointer: UnsafeMutablePointer<ClassMetadataLayout>
@@ -60,15 +77,12 @@ struct ClassMetadata: NominalMetadataType {
6077
fatalError("Cannot get the `genericArgumentOffset` for classes with a resilient superclass")
6178
}
6279

63-
func superClassMetadata() -> ClassMetadata? {
80+
func superClassMetadata() -> AnyClassMetadata? {
6481
let superClass = pointer.pointee.superClass
65-
// type comparison directly to NSObject.self does not work.
66-
// just compare the type name instead.
67-
if superClass != swiftObject() && "\(superClass)" != "NSObject" {
68-
return ClassMetadata(type: superClass)
69-
} else {
82+
guard superClass != swiftObject() else {
7083
return nil
7184
}
85+
return AnyClassMetadata(type: superClass)
7286
}
7387

7488
mutating func toTypeInfo() -> TypeInfo {
@@ -77,12 +91,12 @@ struct ClassMetadata: NominalMetadataType {
7791
info.properties = properties()
7892
info.genericTypes = Array(genericArguments())
7993

80-
var superClass = superClassMetadata()
94+
var superClass = superClassMetadata()?.asClassMetadata()
8195
while var sc = superClass {
8296
info.inheritance.append(sc.type)
8397
let superInfo = sc.toTypeInfo()
8498
info.properties.append(contentsOf: superInfo.properties)
85-
superClass = sc.superClassMetadata()
99+
superClass = sc.superClassMetadata()?.asClassMetadata()
86100
}
87101

88102
return info

Sources/Runtime/Metadata/Metadata.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,12 @@ func swiftObject() -> Any.Type {
5151
let md = ClassMetadata(type: Temp.self)
5252
return md.pointer.pointee.superClass
5353
}
54+
55+
func classIsSwiftMask() -> Int {
56+
#if canImport(Darwin)
57+
if #available(macOS 10.14.4, iOS 12.2, tvOS 12.2, watchOS 5.2, *) {
58+
return 2
59+
}
60+
#endif
61+
return 1
62+
}

0 commit comments

Comments
 (0)