how to debug EXC_BAD_ACCESS on iPhone

October 31, 2009

EXC_BAD_ACCESS. Debugging this one is on par with figuring out why the wife says “not tonight, honey.” And they are equally unfortunate situations.

Let’s see what we can do about EXC_BAD_ACCESS.

EXC_BAD_ACCESS happens when a message is sent to an object that has already been released. By the time the error is caught, the call stack is usually gone especially if dealing with multiple threads.

How nice would it be to keep a dummy around after the object is released that could stop execution, tell us what message was sent and show us the call stack… well, there’s a way to do just that.

If you set the NSZombiEnabled environment variable, the Objective C runtime will leave a dummy object behind for every deallocated object. When the zombie object is called, execution stops and you can see the message that was sent to the object and the call stack that tells you where the message came from (it doesn’t tell you where you over released the object, but knowing where the object is called from should get you pretty close to the problem.)

To set this variable, go to the info panel of the executable in xcode, and create a new environment variable in the arguments tab by clicking the plus sign in the lower left corner of the window. Name the variable NSZombieEnabled, type YES for the value and make sure that the checkbox is selected.

set NSZombieEnabled variable

set NSZombieEnabled variable

Go ahead and run your program now (in debug mode, because you need the stack information.) When the over released object is accessed, you get an error message similar to this (xcode debug view):

2009-03-30 02:30:36.172 ninjaJumper[3997:20b] *** -[GameLayer retain]: message sent
to deallocated instance 0x59bf670

This shows the class of the object (GameLayer) and the message sent (retain).

Let’s take a look at the stack now:

call stack

call stack

The methods printed in bold are in your code, the others are in some other API. Here you can see that the object was accessed from [Director touchesBegan:withEvent], where an array was copied (most likely the over released object was in the array.)

This information should get you pretty close to the problem.

Once the problem is fixed, make sure that the NSZombieEnabled variable is disabled. You don’t need to delete it, but make sure that the checkbox is unchecked:

NSZombie disabled

NSZombie disabled

Now about the wife. Good luck there. Try a box of chocolate or load the dishwasher for a couple days.

65 Responses to “how to debug EXC_BAD_ACCESS on iPhone”

  1. This sounds great! Unfortunately, no more info came through for me… same cryptic EXC_BAD_ACCESS… nothing more. I did set the NSZombieEnabled:YES in the arguments page for the executable… Checkmark too…

  2. Are you running your app in debug mode? What API are you using when you get EXC_BAD_ACCESS?

  3. Hey - thanks for posting…

    Yes, running in debug. 2.2.1 iPhone.

    I later got the results you describe while debugging something else… The one I was working on must be goofy enough to not give these results…

    As a matter of fact, it makes sense (I think) as it turned out to be an issue with passing the pointer to an error (which I wasn’t doing) and thus the object never existed to be “persisted” as a dummy…

    Loose Screw Behind Keyboard (again!) I’m afraid ;)

  4. You rock.

  5. As payment for this stellar, time-saving post, I purchased your Ninja game. I’m already a Ninja, so I should be able to score really high.

  6. Man, you saved me a TON of time. What an awesome tip.

  7. Thanks a lot man, this is a great tip!

  8. Incredible tip! Now if I could only find out why the UITableViewController is being deallocated!

  9. @Mike: Make sure that you are either:
    - retaining it or
    - assigning it to a retaining property

  10. @lajos

    Thanks. I am now retaining it. :-)

  11. You saved my day!!!

  12. Thanks! This just saved my night!

  13. Great post, saved me tons of time!

  14. 2 thumbs up!

  15. This just saved me a LOT of time and confusion. Thank you!

  16. Thank you…

    I spent two days after work , my family was starting to miss me. Finally used your recommendation to find the error, in less than 10 minutes it was fixed.

  17. Awesome, thanks. Now is there any way that “ninjaJumper[3997:20b]” can be displayed in a more useful manner such as “ninjaView.m:line 6 - viewdidLoad”?

  18. Help me, please …

    I spent two weeks with this and I have no idea what could be the problem :(

    EXC_BAD_ACCESS

    *** -[Not A Type release]: message sent to deallocated instance 0×19c0e0

    (sorry for my english)

  19. I have finally found it :)

    CGImageRelease(maskRef);

    Thank for this tip - I would never solve this without it.

  20. THANKS!

  21. This has really, really helped. Thanks for going the extra mile and providing screenshots (esp. for the environment variables). I’ve enabled NSZombieEnabled with my wife and her errors are now much more explicit.

  22. [...] » how to debug EXC_BAD_ACCESS on iPhone codza » how to debug EXC_BAD_ACCESS on iPhone To set this variable, go to the info panel of the executable in xcode, and create a new environment [...]

  23. Nice. After I filled the dish washer a few days, my wife said that I can also clean the windows now, and for birthday she gave me an iron and cleanung gloves wih my name engraved.

  24. Very handy tip! You’ve saved me a lot of time. Now what sucks is my call stack is in the autorelease pool, so I’m starting to suspect a framework I use.

    NSZombieEnabled Works for Mac OS X too, I hear.

  25. How this saved my life. Thank you so much.

  26. Absolute life saver. 6 hours of scouring my first real project that wasn’t running at all until that point and no joy. All other guides I found just re-iterated the same ol rules which is no use when you’re not even sure which file the error is in.

    Obj-c is the scourge of the devil when it comes to memory management and is about as annoying as AOL.

    I come from java & c experience and this is just so much pain compared to both of them, I don’t care what the mac evangelists say.

    Everyone should use java. Most errors are caught at compile time, and the runtime ones point you straight to the problem with a stack trace that is actually useful and doesn’t assume you want to look at assembler code straight away (why does Xcode do that?).

    Anyway, fantastic tip, solved prob this way in <10 mins.

  27. Very useful tip !!

  28. this tip has allowed me to pinpoint my errors very quickly - thanks!

  29. Absolutely PRICELESS. I’ve read millions of threads for so many different things over time and I have never left a comment. Your post warrants eternal thanks.

  30. Thanks for ur post, I must watch what I’m doing with my object management in future. Ha ha.

    Programmer for years, Objective C noob.

  31. thx! very good!

  32. Excellent tip, Lajos. Kind of you to share it with us.

  33. Thanks a lot … it’s really helpful

  34. Hey, could anybody tell me how to see the stack trace. I am unable to find it.

  35. @krazydeveloper: open the debugger (shit+command+y). The call stack is the window in the upper left, you can step back (down?) to find where you are crashing.

  36. @lajos: I got it. Thanks a lot.

  37. thanks! very helpful.

  38. Thanks for the info. Very useful! I actually applied this to Mac OS X and it still works as advertised.

  39. Thanks a lot for the guide. But I still have questions for this.

    I do not know why I could not catch my EXC_BAD_ACCESS, I assumed it working on Device Debug build.

    I got a very strange error in Debug build on device, but no issue for release version. It broke inside a SQL call, sqlite3_prepare_v2->sqlit3_declare_vtab->sqlite3_blob_write.

    If someone can give me some clue I appreciate much!

  40. What if the error is only happening on Device. Say for instance you have:

    #if TARGET_IPHONE_SIMULATOR
    //Simulator calls that cant use PrivateFrameworks in SDK
    #else
    //Private Framework stuff
    #endif

    How would you NSZombie this? Or figure out what KERN_INVALID_ADDRESS at 0×6c707069 pertains to??

  41. @Aaron: NSZombieEnabled keeps deallocated objects around so it’s for debugging overreleased objects. I don’t think you can use it to debug invalid calls into the API.

  42. I am trying to use your tip. It seems that it will help me just as it has helped all these others. But, I don’t know how to “look at the stack now” I do see an over-released variable (I think). It says “-[NSPathStore2 release]: message sent to deallocated instance 0×1441a0.” I have no idea what class that is (I have no such class in my app). And I don’t know how to find that address on the stack since I don’t know how to look at the stack.

    Thanks!

  43. Thank you very much, this made my day! =))

  44. Maybe you create some other object that allocated an instance of NSPathStore2 as its member.

    /quoted ————————/
    Sam Rhoads
    December 18th, 2009 at 5:40 pm
    I am trying to use your tip. It seems that it will help me just as it has helped all these others. But, I don’t know how to “look at the stack now” I do see an over-released variable (I think). It says “-[NSPathStore2 release]: message sent to deallocated instance 0×1441a0.” I have no idea what class that is (I have no such class in my app). And I don’t know how to find that address on the stack since I don’t know how to look at the stack.

    Thanks!

  45. YOU ARE AMAZING. You just saved me hours on a really important project for school. Like, you helped me graduate. YOU ARE THE BEST. Thank you again, and Happy New Year!

  46. Wanted to echo all the other comments and say thanks. Honestly, I was lost with a crash when popping a view controller from the UINavigation controller, which I eventually traced back to an array in my delegate which I’d declared autoRelease when I shouldn’t have. I don’t think I ever would have found it without this.

  47. Thank you very much. This helps a lot.

  48. Great advice about the error. I do remember hearing an adopted grandmother say once, “The sexiest thing she ever saw was her husband doing the dishes”. He said that really worked for him…. into his 80’s.

    Oh and the NSZombiEnabled too.

  49. Thanks a lot! Saved me some hours ;]

  50. I wish I knew this 6 months ago. Thanks for sharing.

  51. Excellent tip! Saved me hours of time tracking down an obscure failure. Thanks!

  52. Thank you! Project so finished I tried to do away with some perceived memory leaks … your tip told me I released a UIArray too much too soon. Now I don’t and it runs smoothly again. I can live with those memory leaks (don’t even remember them!)…

  53. Hi there,
    first of all thanks for your tip.
    I have a question:
    - I set the NSZombieEnabled variable to YES
    - I run my app in debug mode
    - I get from the Debugger Console the “old” message:
    Current language: auto; currently objective-c
    Program received signal: “EXC_BAD_ACCESS”.
    with “xcode debug view” you call the debugger console?
    Where is my error???
    I use Xcode 3.2.1 on Mac OSX Snow Leopard.

    Thanks

  54. @oscar.peli: EXC_BAD_ACCESS means that you are trying to access memory that’s already been freed. It can happen either when you’re overreleasing an object (in which case NSZombieEnabled will tell you the name of the object) or you have a c pointer that’s accessing already freed memory with free(). If you’re sure that you set up NSZombieEnabled correctly and don’t get any information in the debugger console, check the call stack and see if you have issues with malloc/free.

  55. thanks for your answer.
    I suppose that the cause of my error is far away from the point it shows.
    I’m using Core Data and I send child entities to child ViewControllers.
    I use the following code:
    myViewController *myVC = [[myViewController alloc] initWithNibName:@”myNib” bundle:nil];
    myVC.entity = [self entity];
    myVC.managedObjectContext = self.managedObjectContext;
    [self.navigationController pushViewController:myVC animated:YES];
    [myVC release];

    Do you think that the last release cause a memory leak???
    Thanks

  56. @oscar.peli: the navigation controller retains your view controller, so that release is is needed (it would leak if you didn’t release).

  57. i don’t know how you figured this trick out - but damn. thanks a lot for sharing.

  58. Codza… I love you :-) You’ve just saved me thousands of debugging hours in the years to come. Thanks pal.

  59. Great!!

  60. Your tip just helped me fix a bug that had been plaguing me for a few days. Thanks!

  61. Thanks man it ” Solved “;

  62. In my case variable NSZombiEnabled not helped. :( In debugger console I can watch “Program received signal: “EXC_BAD_ACCESS”” message. That is all!

    The CorePlot project is attached to my project. If error happened in CorePlot source is it possible no message about deallocated object?

  63. @Shuriken: NSZombieEnabled only helps with bugs related to accessing released obj-c objects. If the issue is with c pointers accessing freed or unallocated memory, it won’t help. In that case you could check the call stack to get some info about yhe bug.

  64. Stack trace doesn’t get anything:

    #0 0×32916228 in x_heap_free
    #1 0×32915f34 in CALayerLayoutIfNeeded
    #2 0×32915844 in CA::Context::commit_transaction
    #3 0×32915474 in CA::Transaction::commit
    #4 0×3291d5dc in CA::Transaction::observer_callback
    #5 0×31432830 in __CFRunLoopDoObservers
    #6 0×3147a346 in CFRunLoopRunSpecific
    #7 0×31479c1e in CFRunLoopRunInMode
    #8 0×325323a8 in GSEventRunModal
    #9 0×3314ec30 in -[UIApplication _run]
    #10 0×3314d230 in UIApplicationMain
    #11 0×00003090 in main at main.m:14

  65. Thanks for tip. I had learned the same thing in class a few days ago but this was a good reminder. I was able to eventually figure out what was wrong but thread window didn’t give me the method and line name I was looking for. This may be due because my app is multithreaded.

Leave a Reply