EXC_BAD_ACCESS, a Zombie nightmare

Posted on February 25, 2011


Debugging Objective-C on the iPhone is usually OK, but there are some painful moments with those hard to find bugs. Today’s bug went something like this:

1.) Open iPad app in portrait mode
2.) Click on “My Blogs” top left and choose a blog
3.) Make sure you are on the comments view and click ‘edit’ at the top right of that dialog (the button changes to ‘cancel’)
4.) Then when the list is in edit mode rotate the device to landscape mode
5.) The ‘cancel’ button now says ‘edit’. click on this ‘edit’ button.
6.) It should work fine, now simply put the device in portrait mode again and continue from step 2 above.
It should crash the second time you do this, if not it will crash on the third time.

Nice catch. When you are debugging with Xcode, most of the times you get some useful message in the console or at least some stack trace pointing where things went wrong. Today’s message was this useful

Program received signal:  “EXC_BAD_ACCESS”.

And the stack trace was no better:

NSZombie to the rescue

If you have worked with Cocoa for a while, you might be familiar with NSZombie, but since the development tools have changed in the last years, some of the tutorials around are not accurate.

NSZombie is a Cocoa trick that turns any object going to be deallocated into a NSZombie instance. You are going to crash anyway, but instead of Xcode just complaining that you tried to access the wrong memory address, you get something a bit better like this:

2011-02-25 01:27:57.063 WordPress[10496:207] *** -[CFString isEqualToString:]: message sent to deallocated instance 0xcf1b0c0

Not much, but at least you know that the guilty object was a string.

But there’s more to it. First, you enable NSZombie by double clicking your executable in the project info, and then in the “Arguments” tab setting the NSZombieEnabled environment variable

Instruments, that wonderful tool

Sometimes, it will be enough just knowing which class was released more than it should. But when it’s not, Instruments can help.

Sadly, Instruments can only do NSZombie magic on the simulator, but for this example that was not an issue. From Xcode, go to the “Run” menu, then “Run with Performance Tool”, and there you’ll probably see Zombies disabled. Don’t worry, select “Allocations” and you will be fine.

As soon as the app starts running, stop it by clicking on the big record button, we need to set up a few things first.

Click on the little “info” button besides Allocations, and enable “Record reference counts” and “Enable NSZombie detection”. Start the app again (with the same big record button) and repeat the steps that led to the crash. Same story, but this time…

And when you click on that memory address, it will show you the history of the object, when and where it was created, and every time it was retained or released until it crashed

And even more, if you double-click that line, it will take you to a code editor, at the exact line when it was released. Now, that was helpful

And as you can see from this piece of code, we were releasing email on dealloc, but we didn’t retain it on setEmail. Delete that [email release] and problem fixed.

Posted in: Debugging