Scribble uncovering bug in block use I don't understand - xcode

I have a bug which I have uncovered by enabling Scribble in Xcode, fixing the bug is not an issue, it isn't implemented in the best way, I can just remove the whole block, but I don't understand why I am getting the issue in the first place, which tells me I don't understand something
If I have Scribble enabled, when it tries to execute the release line in the code below it crashes without fail,
HDClipPlaybackController * theController = nil;
if( theSource != nil ) {
theController = [[HDClipPlaybackController alloc] initWithClipProxyList:theSource];
}
else {
theController = [[HDClipPlaybackController alloc] initWithClips:clips handles:[handles intValue]];
}
theController.startIndex = [startIndex intValue];
theController.completionHandler = ^(BOOL success){
theController.completionHandler = nil;
[theController release]; // <-- CRASH
};
[theController performSelectorInBackground:#selector(startDownloadingClips:) withObject:theController.clipProxyList.everyClipProxy];
Thread 1: EXC_BAD_ACCESS (code=1, address=0x55555555)
adding a break point on the line before the release line and looking at the value of theController it is a valid object addres but stepping onto the next line I can see the value has changed to 0x55555555 (Scribble has freed it), which I would take to mean that the memory for the block has been freed, since my understanding is that the local variable is copied into the blocks scope, but that would mean the blocks memory is being freed before it has finished executing? If I just move the release to outside the block, the crash goes away, also if I enable Zombies instead of Scribble I don't have any issue, so it doesn't look like an over release issue to me. The variable theController isn't declared __block, so it should just be a simpler pointer inside the block scope if I understand things correctly.
This is a Mac OS X app running as 32bit, with Xcode 6.1.1 and Mac OS 10.9.5.

On the theController.completionHandler = nil; line you remove the last reference to the block, which causes the block to be deallocated. Then on the [theController release]; line, you access the block's captured copy of the theController variable, which is stored in the block. But you already deallocated the block, so you are accessing a field on a deallocated thing.

Related

Memory continuously increase in Instrumentation even with ARC

I am creating an application with ARC enabled and iOS 7 only. My all properties are properly marked as weak and all strong variables are marked as nil where I need it.
When I run my application with Instruments I found that memory allocation is continous increasing. When I go to any screen the memory increases (approximate 2 MB). When I pop that view the memory gets down to only few KBs. I don't know what happening.
while poping a view I am using following:
UPDATE:
[UIView animateWithDuration:0.5 animations:^{
CGRect newFrame = aSideMenu.view.frame;
newFrame.origin = SIDE_MENU_VIEW_ORIGIN_FINAL;
[aSideMenu.view setFrame:newFrame];
} completion:^(BOOL finished) {
[sender setUserInteractionEnabled:YES];
}];
Here I am using aSideMenu in block. aSideMenu is strong variable. Do you think I need to create it's weak reference and use?
__weak id aWeak = aSideMenu;
and use this aWeak instead of aSideMenu?
Also In few block I am using:
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:....nil];
Should I pass weak reference of `dict' too?
I am not sure if this is the reason. Please help me to track the issue. Also let me know if anything else needs to add in this question for better solution.
Thanks
It would be great if you paste your code also. Without code I can just give you some tips.
Like never try to access strong pointer of self in block. Before entering in a block create weak pointer of self.
__weak id weakSelf = self;
and then use weakSelf inside the block.
Better also test your app for unbounded memory growth, where allocated memory never get chance to dealloct, you can take footprints by using Allocation instrument.
Update:
YES because you are calling setter method on strong pointer, it will retain it. You have to make them __weak or __block if they are shared.
https://developer.apple.com/library/ios/documentation/cocoa/conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW1
After having some more code, I want to make some thing more clear about the referenceing in block.
Memory issue may arrise when you reference some strong pointer inside block, as block will not let them deallocat, as they have valid reference, this is the major reason of memory issues. For that we have we create a weak pointer by using __weak id so I will not create a retian cycle.
But there is another issue if object have no other vaild reference, It will be deallocated and weak reference will be nil and it can cause a crash.
So good practice is to create a strong reference to weak in side the block and check for the nil.

How Does NSZombies Really Work?

I cannot find any detailed apple documentation on how the NSZombie really functions. I understand that its designed to not actually release objects and just maintain a count of references to catch any extra releases, but how would something like this work:
for(int i = 1; i < 10; i++)
{
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity: i];
[array release];
}
Since the same variable/object is being allocated/initialized and released in the same application, how would NSZombie's technically handle this? I know that this shouldn't flag any zombies because every alloc has a release, but how would Xcode technically handle re-allocating the same memory with different capacities?
With Zombies, objects don't actually need to be freed[1] -- the object is simply turned into a "Zombie" at some point after the object's retain count reaches 0. When you message a "Zombified" instance, a special error handler is performed.
1) Freeing Zombies is optional. Unless you really need the memory for a long running or memory intensive task, it is a more effective test to not to free the zombies (NSDeallocateZombies = NO)
This question was answered in the comments by Brad Larson.
Quote:
That isn't the same object, or the same memory. You're creating a distinct, new NSMutableArray instance on every pass through that loop. Just because a pointer to each is assigned to array does not make them the same object.
A pointer merely points to a particular location in memory where the object exists. A given object in memory can have multiple pointers to it, or even none (when it is being leaked). NSZombie acts on the object itself, not pointers to it.

Strange XCode debugger behaviour

I am using XCode 4.3.1 and something strange is happening when I debug my app in last few days.
Here is the code:
-(void) init
{
list = [[NSMutableArray alloc]init]; // list is declared in the header
}
-(void) dosomething
{
[self init];
// strangely the debugger shows "list" is still null here
[list addObject: something];
// but it happily steps over the above line without adding anything to the list
}
Another problem (somewhere else in the code) is that sometimes the debugger decides to jump several lines (as if it switches over to another thread but there's only one thread)
The worst part is sometimes when I step over the code it even goes backward a few lines and and then forward again.
I tried to switch to GDB but to no avail. Has anyone run into these problems?
Btw, i was doing some profiling to find memory leaks before these things start happening
The problem is that you are running your project with compiling optimizations, probably because you debug it in release mode ; or because for some reasons you have some compiling optimizations defined in your project settings in debug mode. Check if you have the message hereafter in your XCode console :
[Project Name] was compiled with optimization - stepping may behave oddly; variables may not be available.
If yes, read this : 'Project Name' was compiled with optimization - stepping may behave oddly; variables may not be available

RetainCount Memory not free'ed

I am stuck with the Cocoa Memory Managagment.
- (IBAction) createPush:(UIButton *)sender {
[create setEnabled:NO];
[release setEnabled:YES];
aLocation = [[Location alloc] init];
// Put some Example Stuff in the Class
aLocation.title = #"Apartment";
aLocation.street = #"Examplestreet 23";
aLocation.zip = #"12345";
aLocation.city = #"Exampletown";
aLocation.http = #"http://google.com";
aLocation.info = #"First Info Text";
aLocation.info2 = #"Second Info Text, not short as the first one";
aLocation.logoPath = #"http://google.de/nopic.jpg";
[aLocation.pictures addObject:#"http://google.de/nopic.jpg"];
[aLocation.pictures addObject:#"http://google.de/nopic.jpg"];
}
- (IBAction) releasePush:(UIButton *)sender {
[release setEnabled:NO];
[create setEnabled:YES];
[aLocation release];
aLocation = nil;
}
This Code works fine if I set or get Variables, but when I call the 'last' release (so the retain count is 0) it dealloc Method of aLocation gets called, but in Instruments Allocations you see that no memory is given back.
Here the Sources of Location:
http://homes.dnsalias.com/sof/Location.m
same Link with a '.h' instead of '.m' for the Header file (sorry its because of the Spaming Rule).
And the whole Project: http://homes.dnsalias.com/sof/Location.zip
Thanks for any help, where is my failure? Dennis
This Code works fine if I set or get
Variables, but when I call the 'last'
release (so the retain count is 0) it
dealloc Method of aLocation gets
called, but in Instruments Allocations
you see that no memory is given back.
What do you mean by "no memory is given back"?
Though oddly named, the memory management of aLocation is correct is the above code (assuming you have released it in dealloc as well).
Why doesn't memory use decrease when a single object is released?
(Paraphrased)
It is likely that your object is relatively tiny and, thus, that single deallocation falls below the ~20K or so needed to show up in Instruments.
If your app is crashing due to memory use issues, looking to a single deallocation is the wrong place to start. The first thing to do is to answer why your app is accreting memory and what is responsible for that growth.
Configure the Allocations instrument to only track live allocations. Then sort by total memory use. That'll show you what type of allocation is consuming the most memory. Start by reducing that.
Heapshot analysis can be very effective in these situations.
Additional Infos here because of maximum number of links and I have'nt the opportunity to post images...
What do you mean by "no memory is given back"?
I will show you the Instruments run, then it should be clear.
Screenshots from Instruments run
If want more Detail klick here for Instruments Run.
Your code is just fine. You are mistaken the output from Instruments. There is no Location object leaking.
For leaks, use the "Leaks" instrument. It won't fire. :-)

How to break on __NSAutoreleaseNoPool

I'm getting peppered with
*** __NSAutoreleaseNoPool(): Object 0x1961180 of class NSEvent autoreleased with no pool in place - just leaking
warnings during run-time and have no idea what the cause is. Cursory Googles indicate that this is a symbol I can break on with Xcode, but adding it as a symbolic breakpoint via Run>Manage Breakpoints>Add Symbolic Breakpoint, or simply via the breakpoints management window, results in a breakpoint with a - next to it instead of a check, which I take to mean it's a symbol that can't be found.
I've tried adding the symbol "__NSAutoreleaseNoPool" with two underscores, one underscore, and now I'm just feeling stupid. The errors continue to get logged and no breakpoints get hit. Any pointers for breaking on Obj-C symbols or debugging this would be appreciated.
[EDIT: after maybe 10 (10 more, so a couple dozen total, including at least two Xcode restarts) runs I got "Pending breakpoint 9 - "__NSAutoreleaseNoPool" resolved" printed to my console and the breakpoint started working. Is there any way to force a pending breakpoint to actually resolve?]
To actually answer your question, look in NSDebug.h. There you will find a comment of which this is part:
NAME OF ENV. VARIABLE DEFAULT SET TO...
NSDebugEnabled NO "YES"
NSZombieEnabled NO "YES"
NSDeallocateZombies NO "YES"
NSHangOnUncaughtException NO "YES"
and farther down are these comments:
// Functions used as interesting breakpoints in a debugger
// void __NSAutoreleaseNoPool(void *object);
// Called to log the "Object X of class Y autoreleased with no
// pool in place - just leaking" message. If an environment
// variable named "NSAutoreleaseHaltOnNoPool" is set with string
// value "YES", the function will automatically break in the
// debugger (or terminate the process).
// void __NSAutoreleaseFreedObject(void *freedObject);
// Called when a previously freed object would be released
// by an autorelease pool. If an environment variable named
// "NSAutoreleaseHaltOnFreedObject" is set with string value
// "YES", the function will automatically break in the debugger
// (or terminate the process).
So you don't really need to set these breakpoints; just set the appropriate environment variables. You can do the latter either from your e.g. .bashrc or in Xcode 4 you can edit the "Run" section of your "scheme" and set them there -- that's what I do, and it works just fine.
I have the same issue on setting breakpoint on __NSAutoreleaseNoPool().
I finally successfully set the break point use gdb command.
After debugger started, press ctrl+C in debugger console.
Use "br __NSAutoreleaseNoPool" to set the break point and restart the debugger.
It sounds like you're using Cocoa in a thread somewhere and not wrapping the thread body with an autorelease pool. You probably don't need to use breakpoints to find this. Are you doing any detachNewThreadSelector?
The issue here is simple: You are releasing with no pool in place. This usually happens in command line tools written against Foundation. Simply add the following code to your main(): (Irrelevant parts omitted)
int main (…) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
/// Your code goes here.
[pool drain]; // This one might not strictly speaking be neccessary.
[pool release];
return 0;
}
Edit: If you are not creating a command line tool, chances are you are doing something naughty; but nonetheless: If you have code you invoke before NSApplicationMain(), you need to wrap this in the same basic code, draining and releasing the pool before the invocation of NSApplicationMain.
I know this is an old thread. Just wanted to share some light on the right solution.
The right way to have a breakpoint at _autoreleasenopool is using the breakpoint navigator in xcode.(use the key command+6).
In the bottom left portion of the breakpoint navigator click '+' sign and add symbolic breaakpoint. Enter the symbol as objc_autoreleaseNoPool.

Resources