Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-15612] Initializing NSObject inheritant with default parameter values sometimes results in crash. #57908

Open
swift-ci opened this issue Dec 17, 2021 · 0 comments

Comments

@swift-ci
Copy link
Collaborator

@swift-ci swift-ci commented Dec 17, 2021

Previous ID SR-15612
Radar None
Original Reporter VaslD (JIRA User)
Type Bug
Environment

Configuration 1 that generated dynamic init for PhoneNumberKit class in PhoneNumberKit:

MacBook Pro (Retina, 15-inch, Mid 2015)

macOS 12.1 (21C52)

Xcode 13.2 (13C90)

Apple Swift version 5.5.2 (swiftlang-1300.0.47.5 clang-1300.0.29.30)

Configuration 2 that generated dynamic init for SessionDelegate class in Alamofire:

MacBook Pro (16-inch, 2019)

macOS 11.4 (20F71)

Xcode 13.0 (13A233)

Apple Swift version 5.4 (swiftlang-1205.0.26.9 clang-1205.0.19.55)

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, RunTimeCrash
Assignee None
Priority Medium

md5: ab097cb122fe08360ca130db3553a09b

Issue Description:

If a class inheriting NSObject declares their own inits without overriding super's parameter-less init, and any one of these inits has default values for all parameters, calling the init with default parameter values may result in a runtime crash.

Basically, if I have:

class SomeObject: NSObject {
     var someValue: String

     init(value: String = "SomeObject") {
         self.someValue = value
         super.init()
     }
}

Somewhere the app crashes at a call site SomeObject() with:

Fatal error: Use of unimplemented initializer 'init()'...

Many third-party libraries do this, for example:

Alamofire: SessionDelegate.swift @ Line 38

PhoneNumberKit: PhoneNumberKit.swift @ Line 24

I cannot reproduce this in a brand-new project, but at least two iOS apps I wrote had encountered this problem. The same project that is compiled several times on different machines may get different results. I think I've found some clues to why this is happening, and a way to reproduce it although not entirely straightforward.

When BUILD_LIBRARY_FOR_DISTRIBUTION is turned on for Alamofire, build that crashes has the following Swift Interface generated:

@objc open class SessionDelegate : ObjectiveC.NSObject {
  public init(fileManager: Foundation.FileManager = .default)
  @objc override dynamic public init()
  @objc deinit
}

While the build that doesn't crash is missing the dynamic init in Swift Interface:

@objc open class SessionDelegate : ObjectiveC.NSObject {
 public init(fileManager: Foundation.FileManager = .default)
 @objc deinit
}

So to reproduce, download or write a framework that has a class with all-default-values init. Then archive and generate an XCFramework of it. For Alamofire 5.5.0 the command to create XCFramework from its source directory is:

(Note that you need to turn Build Library for Distribution ON and Skip Intall OFF first for the intended Alamofire target.)

xcodebuild archive -project "Alamofire.xcodeproj" -scheme "Alamofire iOS" -sdk iphoneos -archivePath ./iOS.xcarchive

xcodebuild archive -project "Alamofire.xcodeproj" -scheme "Alamofire iOS" -sdk iphonesimulator -archivePath ./Simulator.xcarchive

xcodebuild -create-xcframework -archive ./Simulator.xcarchive -framework "Alamofire.framework" -debug-symbols "$(pwd)/Simulator.xcarchive/dSYMs" -archive ./iOS.xcarchive -framework "Alamofire.framework" -debug-symbols "$(pwd)/iOS.xcarchive/dSYMs" -output "./Alamofire.xcframework"

Observe if any *.swiftinterface has

@objc override dynamic public init()

for SessionDelegate declaration. If it does, integrating this framework and call

_ = SessionDelegate()

somewhere in the app will crash at runtime.

If the generated framework doesn't have that line, try running the command again on another machine (or at some other time). I have not found exactly what is causing this and how to reproduce it consistently. But since the exactly same code generates different interfaces, I'm fairly certain this is compiler's wrong-doing.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant