Using Zombies in Xcode - ios

I am using Zombies to try and get rid of an EXC_BAD_ACCESS error.
In Zombies, I got this message when the app crashes -
An Objective-C message was sent to a deallocated object (zombie) at
address: 0x8955310.
My question is what do I do next to solve the problem ?

Turn on malloc stack logging and zombies for your scheme in Xcode, and run the app in the simulator. Xcode should enter the debugger when the message is sent to the zombie. Run this command at the debugger prompt:
info malloc 0x8955310
(Substitute the actual address of the zombie!) You'll get stack traces from when that address was allocated and freed.

Most likely you have created an object, released it and later sent it a message.
To make sure this won't happen, a safe practice would be to set your object to nil once you are done using it
Consider:
NSMutableArray *a = [NSmutableArray array];
[a dealloc];
[a do_something_weird];
Your app is likely crash (won't always crash) in response to this message, as after release, you don't own this memory, and it may be used by some other object.
If you change this sequence to
NSMutableArray *a = [NSmutableArray array];
[a dealloc];
a=nil;
[a do_something_weird];
Exactly nothing will happen. This is a safe practice to follow when you are sure you're done using the object.
You also may want to consider using the Automatic Reference Counting feature, which helps a lot with memory management.

Related

Why is my crashing and saying EXC-BAD_ACCESS while trying to show a GKPeerPickerController(ARC is on)

Recently I have come across a problem in an app that I am developing. The app is crashing with EXC_BAD_ACCESS. This doesn't make sense because auto-reference-counting is turned on.
In the app, I have a button that is linked to an IBAction that displays a GKPeerPickerController.
-(IBAction)showPicker:(id)sender
{
picker = [[GKPeerPickerController alloc ] init];
picker.delegate = self;
picker.connectionTypesMask = GKPeerPickerConnectionTypeNearby;
[picker show];
}
This doesn't make sense because if I try to manage the memory with calls such as release, it will give me an error saying that ARC disables that call. So as far as I know there is nothing I can do about it. When it crashes, the EXC_BAD_ACCESS is on the line that allocates and initializes the GKPeerPickerController.
Does this only happen the second time you try to launch the GKPeerPicker?
EXC_BAD_ACCESS is thrown when your app tries to access a memory location which it doesn't 'own'. This can happen in numerous different ways, even with ARC, which makes it a hard crash to diagnose.
Check out this question for e.g. EXC_BAD_ACCESS (SIGSEGV) crash - using NSZombies could be a way to track what's going on.
However, a little more understanding of what's going on might help you to understand this crash and fix it.
The first question is - how is it possible to get EXC_BAD_ACCESS when we're merely assigning a newly allocated object? Well - the 'magic of ARC' is coming in to play here... That simple assignment statement is assigning a new object to an instance variable. The compiler will see that and say - Ah... that ivar might already have an object assigned to it, in which case I'd better release it... So it will add some code for you to check for nil and release the ivar, before it assigns the new value.
So - I find it unlikely that the alloc/init is causing your problem, and more likely that it's whatever is currently stored in your picker ivar... What happens if you make picker a local variable instead of an ivar?
-(IBAction)showPicker:(id)sender
{
GKPeerPickerController *localPicker = [[GKPeerPickerController alloc ] init];
localPicker.delegate = self;
localPicker.connectionTypesMask = GKPeerPickerConnectionTypeNearby;
[localPicker show];
}

iOS 5 blocks crash only with Release Build

I have using blocks and ARC, and found in some situation, iOS only crash in Release build. It was wrong way to write code, like this.
-(IBAction)clickedButtonA:(UIBarButtonItem*)sender event:(UIEvent*)event {
NSMutableArray *arrRows = [NSMutableArray arrayWithCapacity:0];
#warning this code only crash on Release Build.... Don't use this
NSMutableDictionary * dicRow = [NSMutableDictionary dictionaryWithCapacity:0];
[arrRows addObject:dicRow];
dispatch_block_t block = ^{
NSString *str = [NSString stringWithFormat:#"%#",[_tweet valueForKey:#"text"]];
[[UIPasteboard generalPasteboard] setString:str];
};
[dicRow setValue:block forKey:kDicKeyLinkPopBlock];
NSMutableArray *sections = [NSMutableArray arrayWithObject:arrRows];
TOVLinkPopoverViewController *controller= [[TOVLinkPopoverViewController alloc] init];
controller.arrayLink = sections;
}
And from other controller, when I access the block, it crashes only I am on release build. I have learn you need to copy the block
[dicRow setValue:[block copy] forKey:kDicKeyLinkPopBlock];
For non-block aware Class like NSMutableDictionary.
The question is "Why it only crashes on Release build?" I know this "should crash", and this was wrong way of using block, but hoping it crashes on Debug build so we can find this kind of bug earlier.
One more question is "Is there any build setting that makes this code crash with debug build?"
You can ran sample code from gitHub,
https://github.com/tomohisa/iOS_PopoverMenu_Notification
See ViewController.m and find commented out code (only crash on release).
You're right that you need to add [block copy]. This is because that block is created in the current stack frame (i.e. within clickedButtonA:event:) but then you add it to a dictionary and presumably pull it out later. When you pull it out later and use it, that original stack frame has gone and you will have a pointer to some random memory that might not (most likely won't) actually be the block any more.
When you copy the block, if it's on the stack currently then it gets copied to the heap and if it's already on the heap then it just retains it. This means that you now have a block which can be passed around between contexts and will be valid.
The reason that you are only seeing it crash in release mode is because release mode will be turning on compiler optimisation that is completely changing how the stack is handled. Probably you were very lucky in debug mode not to see the problem and was simply a quirk of how your app is designed.

iOS App crashes on exit, how to debug?

My app crashes when I quit it(not press home button and go to background), I guess the problem is that some objects released in viewDidUnload, are released again in dealloc, but I'm not sure. As my code has more than 10000 lines, is there any tool or method so I can quickly pinpoint the bug? Or is it caused by something else rather than one object being released twice?
Thanks!
Here is a screenshot of left pane:
Also, I tried to log messages in viewDidUnload and dealloc, but did not see any error message.
- (void)viewDidUnload {
print "viewDidUnload 1";
// actual method body
print "viewDidUnload 2";
}
the same for dealloc.
Edit 2:
My app uses Core Data, so is there anything I need to manually finalize on exit for Core Data(or it will crash)?
Test it on a real device - if the app crashes, a crash log will be generated. It will be available in the Organizer Window of XCode in Device Logs section corresponding to your device.
That log will give you the call stack of the crash, probably narrowing the places you need to search.
It's hard to say if you have not posted any code.
Do you have any crash logs?
How are you releasing in viewDidUnload?
[_mayVar release]; // 1. on its own this will most likely cause a crash
[_mayVar release]; _myVar = nil; // 2. This is better as sets the pointer to nil
self.myVar = nil; // 3. If you use properties this is easier than line 2
i have the same problem and running it on a real device showed that it crashes in FlurryAnalytics. Do you use that?
I had to remove it completely from the project (not only not starting the session!) to fix this crash.

Should this value be released?

I was getting a segfault 11 memory access error in the IOS Simulator, but it disappears when I comment out the release in the code below.
// get get the question number
NSString *text = [attributeDict valueForKey:XML_TAG_QUESTION_ATTRIBUTE_NUMBER];
question.number = [text intValue];
//[text release]; <==== no more segfault 11 when this is commented out.
My question is, since I am receiving an instance of NS String returned by the NSXMLParser implementation, isn't the reference count increased and should I not be releasing it?
Here's the rule: Always NARC on your memory management.
If you call:
(N)ew
(A)lloc
(R)etain or
(C)opy...
You need to release. If not, you got it through a convenience method and it's autoreleased.
In the case of containers of other objects, the container has the objects retained, and you don't need to worry about it until you release the container.
No it should not.
Read the memory management programming guide : http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/MemoryMgmt/MemoryMgmt.html

EXC_BAD_ACCESS signal received

When deploying the application to the device, the program will quit after a few cycles with the following error:
Program received signal: "EXC_BAD_ACCESS".
The program runs without any issue on the iPhone simulator, it will also debug and run as long as I step through the instructions one at a time. As soon as I let it run again, I will hit the EXC_BAD_ACCESS signal.
In this particular case, it happened to be an error in the accelerometer code. It would not execute within the simulator, which is why it did not throw any errors. However, it would execute once deployed to the device.
Most of the answers to this question deal with the general EXC_BAD_ACCESS error, so I will leave this open as a catch-all for the dreaded Bad Access error.
EXC_BAD_ACCESS is typically thrown as the result of an illegal memory access. You can find more information in the answers below.
Have you encountered the EXC_BAD_ACCESS signal before, and how did you deal with it?
From your description I suspect the most likely explanation is that you have some error in your memory management. You said you've been working on iPhone development for a few weeks, but not whether you are experienced with Objective C in general. If you've come from another background it can take a little while before you really internalise the memory management rules - unless you make a big point of it.
Remember, anything you get from an allocation function (usually the static alloc method, but there are a few others), or a copy method, you own the memory too and must release it when you are done.
But if you get something back from just about anything else including factory methods (e.g. [NSString stringWithFormat]) then you'll have an autorelease reference, which means it could be released at some time in the future by other code - so it is vital that if you need to keep it around beyond the immediate function that you retain it. If you don't, the memory may remain allocated while you are using it, or be released but coincidentally still valid, during your emulator testing, but is more likely to be released and show up as bad access errors when running on the device.
The best way to track these things down, and a good idea anyway (even if there are no apparent problems) is to run the app in the Instruments tool, especially with the Leaks option.
A major cause of EXC_BAD_ACCESS is from trying to access released objects.
To find out how to troubleshoot this, read this document:
DebuggingAutoReleasePool
Even if you don't think you are "releasing auto-released objects", this will apply to you.
This method works extremely well. I use it all the time with great success!!
In summary, this explains how to use Cocoa's NSZombie debugging class and the command line "malloc_history" tool to find exactly what released object has been accessed in your code.
Sidenote:
Running Instruments and checking for leaks will not help troubleshoot EXC_BAD_ACCESS. I'm pretty sure memory leaks have nothing to do with EXC_BAD_ACCESS. The definition of a leak is an object that you no longer have access to, and you therefore cannot call it.
UPDATE:
I now use Instruments to debug Leaks. From Xcode 4.2, choose Product->Profile and when Instruments launches, choose "Zombies".
An EXC_BAD_ACCESS signal is the result of passing an invalid pointer to a system call. I got one just earlier today with a test program on OS X - I was passing an uninitialized variable to pthread_join(), which was due to an earlier typo.
I'm not familiar with iPhone development, but you should double-check all your buffer pointers that you're passing to system calls. Crank up your compiler's warning level all the way (with gcc, use the -Wall and -Wextra options). Enable as many diagnostics on the simulator/debugger as possible.
In my experience, this is generally caused by an illegal memory access. Check all pointers, especially object pointers, to make sure they're initialized. Make sure your MainWindow.xib file, if you're using one, is set up properly, with all the necessary connections.
If none of that on-paper checking turns anything up, and it doesn't happen when single-stepping, try to locate the error with NSLog() statements: sprinkle your code with them, moving them around until you isolate the line that's causing the error. Then set a breakpoint on that line and run your program. When you hit the breakpoint, examine all the variables, and the objects in them, to see if anything doesn't look like you expect.I'd especially keep an eye out for variables whose object class is something you didn't expect. If a variable is supposed to contain a UIWindow but it has an NSNotification in it instead, the same underlying code error could be manifesting itself in a different way when the debugger isn't in operation.
I just spent a couple hours tracking an EXC_BAD_ACCESS and found NSZombies and other env vars didn't seem to tell me anything.
For me, it was a stupid NSLog statement with format specifiers but no args passed.
NSLog(#"Some silly log message %#-%#");
Fixed by
NSLog(#"Some silly log message %#-%#", someObj1, someObj2);
The 2010 WWDC videos are available to any participants in the apple developer program.
There's a great video: "Session 311 - Advanced Memory Analysis with Instruments" that shows some examples of using zombies in instruments and debugging other memory problems.
For a link to the login page click HERE.
Not a complete answer, but one specific situation where I've received this is when trying to access an object that 'died' because I tried to use autorelease:
netObjectDefinedInMyHeader = [[[MyNetObject alloc] init] autorelease];
So for example, I was actually passing this as an object to 'notify' (registered it as a listener, observer, whatever idiom you like) but it had already died once the notification was sent and I'd get the EXC_BAD_ACCESS. Changing it to [[MyNetObject alloc] init] and releasing it later as appropriate solved the error.
Another reason this may happen is for example if you pass in an object and try to store it:
myObjectDefinedInHeader = aParameterObjectPassedIn;
Later when trying to access myObjectDefinedInHeader you may get into trouble. Using:
myObjectDefinedInHeader = [aParameterObjectPassedIn retain];
may be what you need. Of course these are just a couple of examples of what I've ran into and there are other reasons, but these can prove elusive so I mention them. Good luck!
I find it useful to set a breakpoint on objc_exception_throw. That way the debugger should break when you get the EXC_BAD_ACCESS.
Instructions can be found here DebuggingTechniques
Just to add another situation where this can happen:
I had the code:
NSMutableString *string;
[string appendWithFormat:#"foo"];
Obviously I had forgotten to allocate memory for the string:
NSMutableString *string = [[NSMutableString alloc] init];
[string appendWithFormat:#"foo"];
fixes the problem.
Another method for catching EXC_BAD_ACCESS exceptions before they happen is the static analyzer, in XCode 4+.
Run the static analyzer with Product > Analyze (shift+cmd+B).
Clicking on any messages generated by the analyzer will overlay a diagram on your source showing the sequence of retains/releases of the offending object.
Use the simple rule of "if you didn't allocate it or retain it, don't release it".
Run the application and after it fails (Should display "Interrupted" rather than "EXC_BAD_ACCESS"... Check the Console (Run > Console)... There should be a message there now telling what object it was trying to access.
I've been debuging, and refactoring code to solve this error for the last four hours. A post above led me to see the problem:
Property before:
startPoint = [[DataPoint alloc] init] ;
startPoint= [DataPointList objectAtIndex: 0];
.
.
.
x = startPoint.x - 10; // EXC_BAD_ACCESS
Property after:
startPoint = [[DataPoint alloc] init] ;
startPoint = [[DataPointList objectAtIndex: 0] retain];
Goodbye EXC_BAD_ACCESS
Hope you're releasing the 'string' when you're done!
I forgot to return self in an init-Method... ;)
This is an excellent thread. Here's my experience: I messed up with the retain/assign keyword on a property declaration. I said:
#property (nonatomic, assign) IBOutlet UISegmentedControl *choicesControl;
#property (nonatomic, assign) IBOutlet UISwitch *africaSwitch;
#property (nonatomic, assign) IBOutlet UISwitch *asiaSwitch;
where I should have said
#property (nonatomic, retain) IBOutlet UISegmentedControl *choicesControl;
#property (nonatomic, retain) IBOutlet UISwitch *africaSwitch;
#property (nonatomic, retain) IBOutlet UISwitch *asiaSwitch;
I encountered EXC_BAD_ACCESS on the iPhone only while trying to execute a C method that included a big array. The simulator was able to give me enough memory to run the code, but not the device (the array was a million characters, so it was a tad excessive!).
The EXC_BAD_ACCESS occurred just after entry point of the method, and had me confused for quite a while because it was nowhere near the array declaration.
Perhaps someone else might benefit from my couple of hours of hair-pulling.
Forgot to take out a non-alloc'd pointer from dealloc. I was getting the exc_bad_access on my rootView of a UINavigationController, but only sometimes. I assumed the problem was in the rootView because it was crashing halfway through its viewDidAppear{}. It turned out to only happen after I popped the view with the bad dealloc{} release, and that was it!
"EXC_BAD_ACCESS" [Switching to process 330] No memory available to program now: unsafe to call malloc
I thought it was a problem where I was trying to alloc... not where I was trying to release a non-alloc, D'oh!
How i deal with EXC_BAD_ACCESS
Sometimes i feel that when a EXC_BAD_ACCESS error is thrown xcode will show the error in the main.m class giving no extra information of where the crash happens(Sometimes).
In those times we can set a Exceptional Breakpoint in Xcode so that when exception is caught a breakpoint will be placed and will directly intimate the user that crash has happened in that line
NSAssert() calls to validate method parameters is pretty handy for tracking down and avoiding passing nils as well.
I just had this problem. For me the reason was deleting a CoreData managed object ans trying to read it afterwards from another place.
I've been debuging, and refactoring code to solve this error for the last four hours. A post above led me to see the problem:
Property before:
startPoint = [[DataPoint alloc] init] ;
startPoint= [DataPointList objectAtIndex: 0];
x = startPoint.x - 10; // EXC_BAD_ACCESS
Property after:
startPoint = [[DataPoint alloc] init] ;
startPoint = [[DataPointList objectAtIndex: 0] retain];
Goodbye EXC_BAD_ACCESS
Thank you so much for your answer. I've been struggling with this problem all day. You're awesome!
Just to add
Lynda.com has a fantastic DVD called
iPhone SDK Essential Training
and Chapter 6, Lesson 3 is all about EXEC_BAD_ACCESS and working with Zombies.
It was great for me to understand, not just the error code but how can I use Zombies to get more info on the released object.
To check what the error might be
Use NSZombieEnabled.
To activate the NSZombieEnabled facility in your application:
Choose Project > Edit Active Executable to open the executable Info window.
Click Arguments.
Click the add (+) button in the “Variables to be set in the environment” section.
Enter NSZombieEnabled in the Name column and YES in the Value column.
Make sure that the checkmark for the NSZombieEnabled entry is selected.
I found this answer on iPhoneSDK
I realize this was asked some time ago, but after reading this thread, I found the solution for XCode 4.2:
Product -> Edit Scheme -> Diagnostics Tab -> Enable Zombie Objects
Helped me find a message being sent to a deallocated object.
When you have infinite recursion, I think you can also have this error. This was a case for me.
Even another possibility: using blocks in queues, it might easily happen that you try to access an object in another queue, that has already been de-allocated at this time. Typically when you try to send something to the GUI.
If your exception breakpoint is being set at a strange place, then this might be the cause.
I got it because I wasn't using[self performSegueWithIdentifier:sender:] and -(void) prepareForSegue:(UIstoryboardSegue *) right
Don't forget the # symbol when creating strings, treating C-strings as NSStrings will cause EXC_BAD_ACCESS.
Use this:
#"Some String"
Rather than this:
"Some String"
PS - typically when populating contents of an array with lots of records.
XCode 4 and above, it has been made really simple with Instruments. Just run Zombies in Instruments. This tutorial explains it well: debugging exc_bad_access error xcode instruments

Resources