objc_copyClassList: crash EXC_BAD_INSTRUCTION after update to iOS 13.4 / XCode 11.4

Viewed 651

after updating to iOS 13.4 / XCode 11.4

this code

func getSubclassInfos() -> [ClassInfo] {
    let superObject = CityModel.self
    let superClassInfo = ClassInfo(superObject)

    var subclassList = [ClassInfo]()
    var count = UInt32(0)
    guard let classList = objc_copyClassList(&count) else {
        return subclassList
    }
    for i in 0..<Int(count) {
        let clazz = classList[i] // Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
        if let classInfo = ClassInfo(classList[i]),
            let superclassInfo = classInfo.superclassInfo,
            superclassInfo == superClassInfo
        {
            subclassList.append(classInfo)
        }
    }

    return subclassList
}

crashes in line let clazz = classList[i] with EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) in Simulator.

this line wasn't in my original code. It is here to show that the subscript crashes and not ClassInfo(...)

Any idea what I can do about it?

(the code is inspired by List all subclasses of one class)

1 Answers

Just noticed: classList is a total misnomer. The returned result has type AutoreleasingUnsafeMutablePointer<AnyClass>?. Convert it to an UnsafeBufferPointer<AnyClass> first, and then do your processing on that:

func getSubclassInfos() -> [ClassInfo] {
    let superObject = CityModel.self
    let superClassInfo = ClassInfo(superObject)

    var count = UInt32(0)
    guard let classListPointer = objc_copyClassList(&count) else { return [] }

    return UnsafeBufferPointer(start: classListPointer, count: Int(count))
        .map(ClassInfo.init)
        .filter { $0 == superClassInfo }
}
Related