Incorrect codegen with ARC, a switch statement with blocks, and a captured block

Originator:michael.ash
Number:rdar://11329693 Date Originated:26-Apr-2012 05:09 PM
Status:Closed Resolved:Duplicate
Product:Developer Tools Product Version:
Classification: Reproducible:
 
Summary:

A switch statement containing a block which captures another block in the first case: will generate incorrect code for the second case:.

Steps to Reproduce:

Create a new iPhone project in Xcode, then put the following code into the app delegate:

id F(int x, void(^block)(void))
{
    switch(x) {
        case 0:
            return ^{ return block; }();
        
        case 1:
            return nil;
            
    }
    return nil;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    F(1, ^{});
    return YES;
}

Then run the app in the simulator.

Expected Results:

The app should run quietly.

Actual Results:

The app crashes with a stack trace like this:

* thread #1: tid = 0x1f03, 0x00375de3 libobjc.A.dylib`objc_release + 19, stop reason = EXC_BAD_ACCESS (code=2, address=0x1)
    frame #0: 0x00375de3 libobjc.A.dylib`objc_release + 19
    frame #1: 0x00002c1b ARCCrash`F + 203 at PLAppDelegate.m:22
    frame #2: 0x00002d61 ARCCrash`-[PLAppDelegate application:didFinishLaunchingWithOptions:] + 97 at PLAppDelegate.m:28
    frame #3: 0x0044d386 UIKit`-[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1292
    frame #4: 0x0044e274 UIKit`-[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 524
    frame #5: 0x0045d183 UIKit`-[UIApplication handleEvent:withNewEvent:] + 1027
    frame #6: 0x0045dc38 UIKit`-[UIApplication sendEvent:] + 68
    frame #7: 0x00451634 UIKit`_UIApplicationHandleEvent + 8196
    frame #8: 0x01bd4ef5 GraphicsServices`PurpleEventCallback + 1274
    frame #9: 0x014b0195 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 53
    frame #10: 0x01414ff2 CoreFoundation`__CFRunLoopDoSource1 + 146
    frame #11: 0x014138da CoreFoundation`__CFRunLoopRun + 2218
    frame #12: 0x01412d84 CoreFoundation`CFRunLoopRunSpecific + 212
    frame #13: 0x01412c9b CoreFoundation`CFRunLoopRunInMode + 123
    frame #14: 0x0044dc65 UIKit`-[UIApplication _run] + 576
    frame #15: 0x0044f626 UIKit`UIApplicationMain + 1163
    frame #16: 0x00002b1d ARCCrash`main + 141 at main.m:16

Regression:

Unknown.

Notes:

The code in question works fine if the return statement in case 0: is surrounded by braces. By examining the generated assembly and comparing the broken case with the working case, it appears that the compiler is incorrectly generating cleanup code for the second case statement to clean up the block from the first case statement. Specifically, a call to objc_release is emitted for the case 1: code, which is unnecessary and is crashing when, it appears, it accesses stale or uninitialized data on the stack.

Comments

Got the same kind of crash

Seems like capturing any object (not necessarily a block) in a block is enough. I got the same behavior with a CALayer object.

By tomas.franzen at June 11, 2012, 11:13 a.m. (reply...)

I think I found something closely related.

http://stackoverflow.com/questions/9232705/exc-bad-access-when-i-scroll-my-view/10872089#10872089

By BCichowlas at June 3, 2012, 4:46 p.m. (reply...)

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!