Very often, we run an application and we come across a line saying, Thread n: Program received signal: “EXC_BAD_ACCESS”. And when we try to find out the line of code, the problem occurred, we aren’t able to find out.
In this tutorial, we will learn how to track the EXC_BAD_ACCESS instruction, and map it to the exact line where the error occurred.
First let’s discuss why this error occurs. We know that calling release on an object decreases its retain count by 1. And when the retain count reaches 0, dealloc is called on the object, and it is flushed from memory, leaving no traces of that object.
EXC_BAD_ACCESS occurs when we try to send a message to an object that has already been freed. In other words, if we access an object that has already been removed from the memory. And that is the reason we can’t track the exact place where the error occurred, because the object itself is not there in memory.
But there is a way to track the exact line of code where the error occurred – by using the NSZombieEnabled environment variable. So what is this NSZombieEnabled right? I have taken this excerpt from http://www.cocoadev.com/ that very succinctly defines NSZombieEnabled:
“NSZombieEnabled is an environment variable which controls whether the Foundation runtime will use zombies. When zombies are enabled, a deallocated object’s class is dynamically changed to be
_NSZombie, and by default, the memory region is never marked as free, although this can be controlled separately. With NSZombieEnabled, Cocoa sets an object’s isa pointer to the NSZombie class when its retain count drops to zero instead of deallocating it. Then when you send a message to an NSZombie object (i.e., you’re accessing freed data), it raises an exception and tells you where the object lives.”
One very common way is to manually enable NSZombieEnabled and find where the crash occurred. But, this approach is a bit cumbersome, and moreover, we need to disable it after we detect the crash, because, if by any chance we forget to, it will show a leak for every object in instruments.
The good news is, that Instruments provides a very easy way to detect this without the hassle of enabling and disabling the NSZombieEnabled. This is available in Instruments that comes bundled with Xcode 4.0, Xcode 4.1, as well as Xcode 4.3.
For demonstrating, we will use sample code from our previous tutorial that dealt with converting an HTML file to pdf using the iPhone SDK. We just open the drawPdf method in HtmlToPdfDemoViewController.m and add this release statement in the drawPdf method:
NSString *pdfFileName = [documentsDirectory stringByAppendingPathComponent:fileName]; [pdfFileName release]; UIGraphicsBeginPDFContextToFile(pdfFileName, CGRectZero, nil);
Thus we are releasing the pdfFileName variable immediately after we create it, and then access it in the very next line. I have attached the source code in this tutorial too, with this release statement added. Just download the source code and run it. I am using Xcode 4.2 to demonstrate the process. We will click on the generate button once the web view loads.
We will see this:
Though, here it tells us the rough position of where the crash occurs, but usually, it will show a signal like this in our main.m, and we won’t even know what hit us (Spare me, I am a godfather fan).
We will go to the Run icon on top left corner of Xcode, and Press-hold it; a menu will come up as shown below.
From the options, we will select the Profile option, and we will see a screen like this:
From the options we will choose Zombies and click Profile. We will see that Instruments runs our application and launches a screen like this:
In the View option, we can click on the rightmost button to get the right bar display and we can see the extended detail column.
We will again click the generate button. We will see a screen like this:
We will press the arrow as shown in the screenshot, we will see the details of the object that caused the EXC_BAD_ACCESS error, along with the retain count and the event type, (Malloc, Autorelease etc) that caused a change in the retain count.
In the Extended Detail column on the right side, we can see a stack trace of the object that was the culprit. Here, we can see our class too, named HtmlToPdfDemoViewController.
We double click on our class, and we get the exact lines, where the crash happened:
Now that was it. Quite simple right
All the best for the next time you get crashes due to EXC_BAD_ACCESS!
Give me the Code
I am attaching the source code used i this example: Tracking EXC_BAD_ACCESS error.
And don’t panic if the app crashes Till then, Happy Coding