I am having a crash with a Swift -> Objective-C interoperability under Xcode 14 / Swift 5.7 but only when Optimize for Speed is part of the build. There was no issue with this under Xcode 13.4.1 / Swift 5.6 under the same conditions. Typically, this compiler option is disabled for Debug builds so this was only detected once we provided release builds to beta users using Test Flight.
The interoperability is with using a proprietary, third-party framework. I am not privy to the Objective-C code that makes up the public API for this framework. As the framework had worked with Xcode 13.4.1 (with and without the speed optimization) and also works in Debug mode with Xcode 14.x (I have tried 14.1 as well) but crashes with the speed optimization turned on, I suspect the optimization may be at fault. But it is hard to say. I am hoping someone with better knowledge than I of this can guide me as to why this is happening…and only now.
Here is an example of the code. Note: there are multiple instances of this same pattern in the API. There are vendor supplied structures (as well as NSArray as in this example) that cause similar failure. The vendor has supplied only Objective-C sample code and documentation.
func listItems() {
var availableItems: NSMutableArray? = NSMutableArray()
let result = itemSDK.getAvailableItemList(&availableItems)
// ...
}
The header file provides:
- (ITEM_RESULT) getAvailableItemList:(NSMutableArray**)getAvailableItemList;
The derived Swift interface for this is:
func getAvailableItemList(_ availableItemsList: AutoreleasingUnsafeMutablePointer<NSMutableArray?>!) -> ITEM_RESULT
The crash occurs when calling the API and/or attempting to use the value associated with the AutoreleasingUnsafeMutablePointer.
I have turned on all memory management diagnostics for the run phase of the scheme. When I do so, I see the following in the console when I get a fatal Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1d66e8a88)
presented in the caller to the listItems()
method.
*** -[__NSArrayM retain]: message sent to deallocated instance 0x28bd15200
My assumption is that this indicates the memory was released (aggressively?) and so this causes the crash. Again, only with the -O (Optimize for Speed) option is enabled.
I have been able to code a potential solution to this issue. Maybe this should have been the solution for prior Swift versions…but I had no reason (as it had worked without issue up until Xcode 14).
func listItems() {
let itemsArray = NSMutableArray()
var availableItems: NSMutableArray? = itemsArray
let result = itemSDK.getAvailableItemList(&availableItems)
// ...
}
This solution assigns the array to an immutable variable and then assigns that reference to an optional that is passed for the AutoreleasingUnsafeMutablePointer. My assumption is that adds an additional retain to keep the optimization from removing the memory for the array until the itemsArray
is no longer referenced.
I am reaching out to see if this is a known issue by others and/or expected (but new) behavior as I do not have much experience with AutoreleasingUnsafeMutablePointer. Also, if this is not a bug but is the new normal, is the potential solution the proper way to use the AutoreleasingUnsafeMutablePointer with Objective-C framework APIs? Or should I be doing something different?
Thanks for any insight or pointers (even if unsafe).