Assigning [Int] to [Any] crashes Swift 2.2


(Jens Alfke) #1

Just ran into a weird crash with Swift 2.2 in Xcode 7.3. It reproduces in a playground:

import Foundation
let a = [88]
let b: [Any] = a // CRASH

In my real program, the top of the crash backtrace is:

* thread #1: tid = 0x460b62, 0x000000010669988b libswiftCore.dylib`swift_unknownRetain + 27, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x58)
    frame #0: 0x000000010669988b libswiftCore.dylib`swift_unknownRetain + 27
    frame #1: 0x0000000106488565 libswiftCore.dylib`Swift._arrayConditionalBridgeElements <A, B> (Swift.Array<A>) -> Swift.Optional<Swift.Array<B>> + 1029
    frame #2: 0x00000001064875a7 libswiftCore.dylib`Swift._arrayForceCast <A, B> (Swift.Array<A>) -> Swift.Array<B> + 263

It’s interesting that the memory address causing the crash is 0x58, which in decimal is 88, the first item in the array. If you change the first item of the array to a different number, the crash address changes to match. So it’s misinterpreting the integer as a pointer.

Also interestingly, if you remove “import Foundation”, it no longer compiles — the last line gets an error “Cannot convert value of type ‘[Int]’ to expected argument type ‘[Any]’”. Is boxing of integers really dependent on Obj-C bridging?

—Jens

PS: Should I file the bug report with Apple or at swift.org?


(Joe Groff) #2

This is a known bug. Converting arrays of value type to arrays of protocol type is not supported—only class covariance is supported with containers—but the compiler fails to catch some cases.

-Joe

···

On Apr 13, 2016, at 9:09 PM, Jens Alfke via swift-users <swift-users@swift.org> wrote:

Just ran into a weird crash with Swift 2.2 in Xcode 7.3. It reproduces in a playground:

import Foundation
let a = [88]
let b: [Any] = a // CRASH

In my real program, the top of the crash backtrace is:

* thread #1: tid = 0x460b62, 0x000000010669988b libswiftCore.dylib`swift_unknownRetain + 27, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x58)
    frame #0: 0x000000010669988b libswiftCore.dylib`swift_unknownRetain + 27
    frame #1: 0x0000000106488565 libswiftCore.dylib`Swift._arrayConditionalBridgeElements <A, B> (Swift.Array<A>) -> Swift.Optional<Swift.Array<B>> + 1029
    frame #2: 0x00000001064875a7 libswiftCore.dylib`Swift._arrayForceCast <A, B> (Swift.Array<A>) -> Swift.Array<B> + 263

It’s interesting that the memory address causing the crash is 0x58, which in decimal is 88, the first item in the array. If you change the first item of the array to a different number, the crash address changes to match. So it’s misinterpreting the integer as a pointer.

Also interestingly, if you remove “import Foundation”, it no longer compiles — the last line gets an error “Cannot convert value of type ‘[Int]’ to expected argument type ‘[Any]’”. Is boxing of integers really dependent on Obj-C bridging?

—Jens

PS: Should I file the bug report with Apple or at swift.org?


(Jens Alfke) #3

Thanks for the info!

I found that if I use AnyObject instead of Any, it does work correctly. Is that because AnyObject isn’t a protocol? Or because conversion to AnyObject is a ‘magic’ case that uses Obj-C bridging?

My intuition is that [Any] will be more efficient than [AnyObject] for primitive values like numbers, because the AnyObject conversion boxes the value into a heap object, while converting to Any doesn’t. Or is that incorrect?

—Jens

···

On Apr 14, 2016, at 9:00 AM, Joe Groff <jgroff@apple.com> wrote:

This is a known bug. Converting arrays of value type to arrays of protocol type is not supported—only class covariance is supported with containers—but the compiler fails to catch some cases.


(Joe Groff) #4

This is a known bug. Converting arrays of value type to arrays of protocol type is not supported—only class covariance is supported with containers—but the compiler fails to catch some cases.

Thanks for the info!

I found that if I use AnyObject instead of Any, it does work correctly. Is that because AnyObject isn’t a protocol? Or because conversion to AnyObject is a ‘magic’ case that uses Obj-C bridging?

Yeah, it's magic. Int is bridged to NSNumber, so converting to an array of object type works via the bridge.

-Joe

···

On Apr 14, 2016, at 9:24 AM, Jens Alfke <jens@mooseyard.com> wrote:

On Apr 14, 2016, at 9:00 AM, Joe Groff <jgroff@apple.com> wrote:

My intuition is that [Any] will be more efficient than [AnyObject] for primitive values like numbers, because the AnyObject conversion boxes the value into a heap object, while converting to Any doesn’t. Or is that incorrect?

—Jens