Re: Bad EXC_BAD_INSTRUCTION on drawRect call in Swift
Re: Bad EXC_BAD_INSTRUCTION on drawRect call in Swift
- Subject: Re: Bad EXC_BAD_INSTRUCTION on drawRect call in Swift
- From: Greg Parker <email@hidden>
- Date: Mon, 25 Aug 2014 14:16:51 -0700
On Aug 24, 2014, at 12:44 PM, Fritz Anderson <email@hidden> wrote:
> On Aug 22, 2014, at 11:25 PM, Peters, Brandon <email@hidden> wrote:
>> ArnoldTransformer2`@objc ArnoldTransformer2.ATView.drawRect (ArnoldTransformer2.ATView)(C.CGRect) -> () at ATView.swift:
>
> So this is the very end of your drawRect(_:CGRect) method in (am I right?) class ATView, subclass of UIView (I’m guessing iOS because of the use of CGRect, but you really should say so when you ask questions), part of your application ArnoldTransformer2. Yes?
>
>> 0x10000e550: pushq %rbp
>> 0x10000e551: movq %rsp, %rbp
>> 0x10000e554: subq $0x30, %rsp
>
> [Make room for an additional 48 bytes in the stack.]
>
>> 0x10000e558: leaq 0x10(%rbp), %rax
>> 0x10000e55c: movsd (%rax), %xmm0
>> 0x10000e560: movsd 0x8(%rax), %xmm1
>> 0x10000e565: movsd 0x10(%rax), %xmm2
>> 0x10000e56a: movsd 0x18(%rax), %xmm3
>> 0x10000e56f: movq %rdi, -0x8(%rbp)
>> 0x10000e573: movsd %xmm2, -0x10(%rbp)
>> 0x10000e578: movsd %xmm3, -0x18(%rbp)
>> 0x10000e57d: movsd %xmm0, -0x20(%rbp)
>> 0x10000e582: movsd %xmm1, -0x28(%rbp)
>> 0x10000e587: callq 0x100018f1a ; symbol stub for: objc_retain
>> 0x10000e58c: movsd -0x20(%rbp), %xmm0
>> 0x10000e591: movsd -0x28(%rbp), %xmm1
>> 0x10000e596: movsd -0x10(%rbp), %xmm2
>> 0x10000e59b: movsd -0x18(%rbp), %xmm3
>> 0x10000e5a0: movq -0x8(%rbp), %rdi
>> 0x10000e5a4: movq %rax, -0x30(%rbp)
>> 0x10000e5a8: callq 0x10000bc60 ; ArnoldTransformer2.ATView.drawRect (ArnoldTransformer2.ATView)(C.CGRect) -> () at ATView.swift:224
>
> This instruction is a call to drawRect(_:CGRect). (Attention world: it’s a _direct_ call!) In fact, it looks to be a recursive call to this very function.
It is not. Time for Today's Lesson In Swift's Generated Code!
** Today's Lesson In Swift's Generated Code **
The interface for a pure-Swift function often differs from the interface to the corresponding Objective-C function. For example, Swift may use a different retain/release convention than Objective-C, or Swift may use a closure struct where Objective-C uses a block object, or Swift may use a Swift.String where Objective-C uses an NSString. In such cases the compiler will generate a pure-Swift function plus an additional wrapper for Objective-C's use that translates the parameters and return value appropriately.
The disassembly here is one of those wrapper functions. Note carefully the demangled symbol names:
@objc ArnoldTransformer2.ATView.drawRect (ArnoldTransformer2.ATView)(C.CGRect) -> ()
calls
ArnoldTransformer2.ATView.drawRect (ArnoldTransformer2.ATView)(C.CGRect) -> ()
The first is the Objective-C compatible wrapper function. The second is the Swift function. No recursion or improper calls to -drawRect: here.
Back to the original code:
> if self.contentView!.frame.size.width > photo.size.width {
> docRect.size.width = self.contentView!.frame.size.width
> imageLocation.origin.x = (self.contentView!.frame.size.width - photo.size.width) / 2.0
> }
Several of Swift's safety checks turn into EXC_BAD_INSTRUCTION on x86_64. These safety checks include array bounds checks, integer overflow checks, and nil checks. In the code above, my guess is that it is dereferencing the optional self.contentView value and getting nil back.
Alternatively, it's possible that the failure is not actually at that line. The backtrace for check failures sometimes blames the first line of the function no matter where the failure actually was.
(Yes, we have a bug report that these check failures are too hard to debug.)
--
Greg Parker email@hidden Runtime Wrangler
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden