I was having trouble symbolicating some code in distribution build and finally created a simple project which has a button that basically causes a crash by accessing an objectAtIndex in an array that doesn't exist.
In release (or distribution) build the trace comes up like this when symbolicated where MyApp function calls are completely missing:
0- CoreFoundation 0x34dcb29e __exceptionPreprocess + 158
1 libobjc.A.dylib 0x3537397a objc_exception_throw +26
2 CoreFoundation 0x34d16b70 -[__NSArrayM objectAtIndex:] + 160
3 UIKit 0x311a40a0 -[UIApplication endAction:to:from:forEvent:] + 68
4 UIKit 0x311a4052 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 26
5 UIKit 0x311a4030 -[UIControl sendAction:to:forEvent:] + 40
6 UIKit 0x311a38e6 -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 498
...
In debug build it shows MyApp functions where the code causing the crash is:
0 CoreFoundation 0x34dcb29e __exceptionPreprocess + 158
1 libobjc.A.dylib 0x3537397a objc_exception_throw + 26
2 CoreFoundation 0x34d16b70 -[__NSArrayM objectAtIndex:] + 160
3 MyApp 0x00098128 -[ViewController processArray] (ViewController.m:58)
4 MyApp 0x0009814e -[ViewController Crash:](ViewController.m:63)**
5 UIKit 0x311a40a0 -[UIApplication sendAction:to:from:forEvent:] + 68
6 UIKit 0x311a4052 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 26
7 UIKit 0x311a4030 -[UIControl sendAction:to:forEvent:] + 40
8 UIKit 0x311a38e6 -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 498
The above traces are off the device logs after performing identical tests of deploying and clicking on the button.
Several articles/blogs/questions on SO have talked about symbolication issues where hex symbols are shown instead of method name etc (which is different from this problem) and I've tried deleting stuff from derived data, cleaned out the build directory etc but this can be consistently reproduced. Can anyone please explain why this is happening.
EDIT: Adding the code for easy reference:
-(void) processArray
{
NSMutableArray *array = [NSMutableArray arrayWithObjects:@"One", @"Two", @"Three", nil];
[array objectAtIndex:3];//Intentional crash for testing
}
- (IBAction)Crash:(id)sender
{
[self processArray];
}
Try turning off compiler optimizations and reproducing the crash in the release build.
I suspect that you are getting bitten by a tail call optimization. The compiler may issue instructions that JMP directly from the end of your method to whatever method is called.
i.e. in this case:
- (void)boo
{
[self bangAGong];
}
Since there is no return value, etc... the compiler can rewrite the call to bangAGong
such that it reuses the current stack frame. This is called tail calling (and is also how objc_msgSend()
works. By doing this, it eliminates a pop of the frame on return.
This makes your code run slightly faster, but also means that it'll appear like stack frames are dropped from crash reports.