Skip to content

Commit

Permalink
Merge pull request #62 from ddddxxx/fix-objc-derived-class
Browse files Browse the repository at this point in the history
fix: crash when inspect class that derived from pure objc class
  • Loading branch information
wickwirew authored Dec 4, 2019
2 parents 3e99509 + bbee4dc commit 5638402
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 10 deletions.
15 changes: 13 additions & 2 deletions Sources/Runtime/Layouts/ClassMetadataLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,22 @@

import Foundation

// Swift class or objc class
struct AnyClassMetadataLayout {
var _kind: Int // isaPointer for classes
var superClass: Any.Type
var objCRuntimeReserve: (Int, Int)
var rodataPointer: Int

var isSwiftClass: Bool {
return (rodataPointer & classIsSwiftMask()) != 0
}
}

struct ClassMetadataLayout: NominalMetadataLayoutType {
var _kind: Int // isaPointer for classes
var superClass: Any.Type
var objCRuntimeReserve1: Int
var objCRuntimeReserve2: Int
var objCRuntimeReserve: (Int, Int)
var rodataPointer: Int
var classFlags: Int32
var instanceAddressPoint: UInt32
Expand Down
30 changes: 22 additions & 8 deletions Sources/Runtime/Metadata/ClassMetadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,23 @@

import Foundation

struct AnyClassMetadata {

var pointer: UnsafeMutablePointer<AnyClassMetadataLayout>

init(type: Any.Type) {
pointer = unsafeBitCast(type, to: UnsafeMutablePointer<AnyClassMetadataLayout>.self)
}

func asClassMetadata() -> ClassMetadata? {
guard pointer.pointee.isSwiftClass else {
return nil
}
let ptr = pointer.raw.assumingMemoryBound(to: ClassMetadataLayout.self)
return ClassMetadata(pointer: ptr)
}
}

struct ClassMetadata: NominalMetadataType {

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

func superClassMetadata() -> ClassMetadata? {
func superClassMetadata() -> AnyClassMetadata? {
let superClass = pointer.pointee.superClass
// type comparison directly to NSObject.self does not work.
// just compare the type name instead.
if superClass != swiftObject() && "\(superClass)" != "NSObject" {
return ClassMetadata(type: superClass)
} else {
guard superClass != swiftObject() else {
return nil
}
return AnyClassMetadata(type: superClass)
}

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

var superClass = superClassMetadata()
var superClass = superClassMetadata()?.asClassMetadata()
while var sc = superClass {
info.inheritance.append(sc.type)
let superInfo = sc.toTypeInfo()
info.properties.append(contentsOf: superInfo.properties)
superClass = sc.superClassMetadata()
superClass = sc.superClassMetadata()?.asClassMetadata()
}

return info
Expand Down
9 changes: 9 additions & 0 deletions Sources/Runtime/Metadata/Metadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,12 @@ func swiftObject() -> Any.Type {
let md = ClassMetadata(type: Temp.self)
return md.pointer.pointee.superClass
}

func classIsSwiftMask() -> Int {
#if canImport(Darwin)
if #available(macOS 10.14.4, iOS 12.2, tvOS 12.2, watchOS 5.2, *) {
return 2
}
#endif
return 1
}

0 comments on commit 5638402

Please sign in to comment.