Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iPhone Development - EXC_BAD_ACCESS error with no stack trace

Tags:

cocoa-touch

Here's my case: I have a table view showing contacts. Add button in the navigation bar is used to load another view for data entry. This new view has images in table header, and each table cell has either a UITextField or a UITextView. When i press Cancel, the view is popped out and memory is released.

Here's my issue: When i open the "Add" interface, provide a value in any of the UITextField or UITextView, and press "Cancel" to to go back to the parent view, i get an EXC_BAD_ACCESS error. When i trace it, the "Add Controller" calls dealloc properly, but after the [super dealloc] when i press Continue, it throws this error. Just this, no trace, although i'm using NSZombieEnabled. When i run the code with Instruments, i don't get any error :(

I hope i'm clear in explaining the issue. Any pointers? Thanks.

like image 272
Mustafa Avatar asked Jan 22 '09 09:01

Mustafa


People also ask

What does thread 1 Exc_bad_access mean?

EXC_BAD_ACCESS means that message was sent to a point in the memory where there's no instance of a class to execute it. Thus “bad access”. You will get EXC_BAD_ACCESS in 3 cases: An object is not initialized.

What is Exc_bad_access in Swift?

What does EXC_BAD_ACCESS mean? EXC_BAD_ACCESS is an exception raised as a result of accessing bad memory. We're constantly working with pointers to memory in Swift that link to a specific memory address. An application will crash whenever we try to access a pointer that is invalid or no longer exists.


3 Answers

The most common cause of this error is when you release an object and some other mechanism tries to access/release/dealloc it later.

Whenever I get a report of an EXC_BAD_ACCESS error, my first recommendation is to step through the code to determine which line is causing it, and then to search for any explicit [object release] calls that reference that object. Comment them out one-by-one to find where you may have gone wrong (and, of course, make sure the object is properly released later).

If the line doesn't help you figure out which object(s) is/are causing the problem, start looking through your [object release] calls, and make sure you aren't releasing objects too many times by accident, or releasing objects you don't own.

This leads to a good general guideline regarding release in Objective-C:

If you own an object (allocate or retain it), you release it. If you don't own it (came via convenience method or someone else allocated it), you don't release it.

(Via Memory Management with Objective C / Cocoa / iPhone, which also has some good tips.)

like image 123
breakingobstacles Avatar answered Nov 23 '22 18:11

breakingobstacles


Although this is most often a result of mismanaged memory, it can happen for other reasons (and be harder to debug than simply turning on NSZombieEnabled). For example, if you fail to supply the correct number of arguments to a format string (i.e. while debugging another problem with NSLog), you could end up with no stack trace even with all debugging arguments enabled. Luckily, you can use GDB within Xcode to restore the stack trace to a previous state.

In the GDB console you should see the instruction that crashed your program. Locate the last successful return instruction before the one that failed. It should look something like this:

je    0x986cef35 <objc_msgSend+117>

Note the hex value and execute the following in GDB:

set $eip = 0x986cef35
stepi
where

You should (hopefully) have a more informative stack trace now.

Source (same as the link above)

like image 36
Cameron Spickert Avatar answered Nov 23 '22 17:11

Cameron Spickert


Cameron Spickert's answer is a little deprecated, since Xcode uses lldb now instead of gdb. The link to the source article is also dead.

The same thing can be done rather simply with the following lldb command:

(lldb) thread backtrace

This will show the bt for the current thread. If you want to change the thread from which you want to get the bt, select the frame and get it like this:

(lldb) thread list
(lldb) thread select 2
(lldb) thread backtrace

If you want to replicate the exact behavior of Cameron Spickert's answer, use the following commands:

(lldb) expr unsigned int $eip = 0x1979c81d4
(lldb) stepi
(lldb) thread backtrace

Source 1

Source 2

like image 22
mithunc Avatar answered Nov 23 '22 19:11

mithunc