While writing an iPhone application, I kept getting a mysterious crash during execution. There were no warnings or errors, but when I got to a specific point every time, it would crash. I decided to examine the console for messages. I found the message "EXC_BAD_ACCESS" there.
I Googled this message and found this site on setting the environment variables NSZombieEnabled and MallocStackLoggingNoCompact.
A little background
NSZombieEnabled - If I'm understanding this correctly, when this environment variable is set to YES, when an object is deallocated, instead of releasing it, the compiler will set its type to _NSZombie. Because the memory is never freed, the object remains on the stack, but its type is now _NSZombie. With a little command line usage, you can see where it was attempted to be freed, and whether or not it is intentional.
MallocStackLoggingNoCompact - "causes malloc to remember the caller requesting each allocation, and remembers it after the allocation is freed." (from Mac OSX Reference Library)
To set the environment variables, use this procedure:
- Ctrl+Click on the executable in your project
- Select "Get Info"
- Select "Arguments" tab
- Enter the variable information as seen in the screenshot below
Now, when I run the program, at the point of the crash, the console says:
2010-03-01 19:13:46.924 CruzNomad[7952:207] * -[CFString stringByAddingPercentEscapesUsingEncoding:]: message sent to deallocated instance 0x58448e0
At the gdb prompt, I issued the command: info malloc-history 0x58448e0. This gave me the object's allocation/ deallocation history:
Alloc: Block address: 0x058448e0 length: 64 Stack - pthread: 0xa0b33500 number of frames: 25 0: 0x98e089bc in malloc_zone_malloc 1: 0x21516aa in _CFRuntimeCreateInstance 2: 0x2152bf8 in __CFStringCreateImmutableFunnel3 3: 0x21567d9 in CFStringCreateCopy 4: 0x21742fc in _CFStringCreateWithFormatAndArgumentsAux 5: 0xdb546 in -[NSPlaceholderString initWithFormat:locale:arguments:] 6: 0xdb4d8 in +[NSString stringWithFormat:] 7: 0x23aa3 in -[BuisnessCardViewController viewDidLoad] at /Users/.../Classes/BuisnessCardViewController.m:85 8: 0x3d6796 in -[UIViewController view] 9: 0x347b4 in -[gm_menuViewController btn5_Pressed:] at /Users/.../Classes/menuViewController.m:535 10: 0x357459 in -[UIApplication sendAction:to:from:forEvent:] 11: 0x3baba2 in -[UIControl sendAction:to:forEvent:] 12: 0x3bcdc3 in -[UIControl(Internal) _sendActionsForEvents:withEvent:] 13: 0x3bbb0f in -[UIControl touchesEnded:withEvent:] 14: 0x370e33 in -[UIWindow _sendTouchesForEvent:] 15: 0x35a81c in -[UIApplication sendEvent:] 16: 0x3610b5 in _UIApplicationHandleEvent 17: 0x2984ed1 in PurpleEventCallback 18: 0x2197b80 in CFRunLoopRunSpecific 19: 0x2196c48 in CFRunLoopRunInMode 20: 0x298378d in GSEventRunModal 21: 0x2983852 in GSEventRun 22: 0x362003 in UIApplicationMain 23: 0x2c8c in main at /Users/.../source/main.m:14 24: 0x2bfa in start
Line 7 says the problem was in line 85 of BuisnessCardViewController.m. That line is here:
fullAddress= [NSString stringWithFormat:@"%@ %@", fullAddress, myString];
I read that the method
stringWithFormat:returns an autorelease object. I had to retain the variable right after its first usage, earlier in the method.
fullAddress = [NSString stringWithFormat:@"%@ %@", fullAddress, myString]; [fullAddress retain];
I use it a few times in the implementation file. This is the first operation I perform on it, so I decided to retain it here.
I posted this question on StackOverflow and the iPhone Developer Forums (you need a login for the latter).
Such a rewarding feeling to get an issue debugged!