ARC issue when casting NSObject to class protocols

Originator:666tos
Number:rdar://33536231 Date Originated:26-Jul-2017 13:02
Status:Open Resolved:
Product:iOS + SDK Product Version:10.3
Classification:Security Reproducible:Always
 
Summary:
Object is overreleased under special conditions

Steps to Reproduce:
Run attached code and execute buttonBreakObjectPressed.

Expected Results:
testObject variable is not deallocated.

Actual Results:
testObject constant is deallocated still being strongly referenced by MainViewController.

Version:
10.3

Notes:
There is slight difference between Holder’s getObject and getCrashingObject methods - last one is contained inside switch case block.
To reproduce this issue, few things required: 
- TestProtocol must be class
- TestClass must be NSObject descendant.


class Holder {
    fileprivate weak var reference: AnyObject?
    
    init(reference: AnyObject) {
        self.reference = reference
    }
    
    func getObject<T>() -> T? {
        return self.reference as? T
    }
    
    func getCrashingObject<T>() -> T? {
        switch (self.reference) {
            case is T:
                return self.reference as? T
            default:
                return nil
        }
    }
}

public protocol TestProtocol: class {
    func foo()
}

class TestClass: NSObject, TestProtocol {
    deinit {
        print("TestClass deinit!")
    }

    func foo() {
        
    }
}

class MasterViewController: UIViewController {
    
    let testObject = TestClass()
    
    @IBAction func buttonBreakObjectPressed() {
        print("buttonBreakObjectPressed")
        
        let holder = Holder(reference: self.testObject)
        
        guard let testProtocol: TestProtocol = holder.getCrashingObject() else {
            return
        }
        
        testProtocol.foo()
    }
    
    @IBAction func buttonUseObjectPressed() {
        print("buttonUseObjectPressed")
        
        let holder = Holder(reference: self.testObject)
        
        guard let testProtocol: TestClass = holder.getObject() else {
            return
        }
        
        testProtocol.foo()
    }
}

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!