Incorrect decrement error, code review - objective-c

This code down below works as expected, cleans things up without Zombies. The class in which this method exists, is the owner of the Nodes, which are being released, yet, upon "Analyze" the following 2 issues show up.
If possible, could you help me understand why?
- (void) dealloc {
NSLog(#"Releasing [Doubly Linked List] .. ");
Node *thisNode = [self firstNode];
Node *nextNode = [thisNode next];
while (nextNode != nil) {
// If "Next node" is not nil, it means that
// "previous node" can now be released
NSLog(#" - releasing node \"%c\"", [[nextNode previous] charData]);
[[nextNode previous] release];
nextNode = [nextNode next];
}
[[self lastNode] release];
[super dealloc];
}

Click on the icon on the left of the message, it will show the path through the code that produces the error.
You are releasing something, [nextNode previous] that you do not own. In particular you did not alloc or retain it nor obtain it from a method that begins with new or copy so you do not have ownership of it and should not release it.
It is also very uncommon to release something not in your class, [[nextNode previous] release].
Now: [[self lastNode] release];
As above you did not obtain an ownership on the object you are releasing.
If lastNode is a property with retain you are subverting the setter and when later a value is assigned to lastNode via the setter there will be an extra release on the object and probably a crash. If it is not a property again this it very non-standard to release something that is returned by a method call.
Any releases with code of this form [[self lastNode] release] is non-standard and if be avoided there will be fewer ownership (retain/release) problems.
You will save a lot of time and grief by studying the Apple memory management documentation.

The issue is that you are not doing things according to the ordinary memory management conventions of Objective C and the static analyzer is getting confused. Basically, the Objective C class which allocates an object "owns" the object and is responsible for releasing it. Here, you are not using those conventions, so the analyzer is complaining, even if what you are doing works correctly.
See Apple's documentation for more on ownership.

Related

Basic memory management confusion

I bet that I could find the answer of this question from reading similar threads here or by googling, but I would like "hear" it first hand so to speak because it's an anomaly in my understanding.
So here's the thing, I have some code which a previous employee wrote and I see a lot of a certain type of construct which looks rather odd to me and I just want to clarify what is "right and wrong".
For example
- (void) setWwanServiceId: (NSString *) newValue {
[wwanServiceId autorelease];
wwanServiceId = [newValue copy];
}
Here wwanServiceIdis a NSString member of the class, and to me this seem like a strange way to do it. As far as I understand it would begin by putting an autorelease on the object, basically saying: "whenever this object seem to not be used, release it for me I don't really care" then the copy will up the retain count +1 on.... wwanServiceId? or newValue? I guess the first.
Then to make me all more confused let's just quickly run through the life-cycle of the wwanServiceId-string..
basically the value will be set if we receive a notification which then from the notification-handler method will call the above -setWwanServiceId: method. other than that it will only ever be accessed for reading, so we are safe to say that it will at any given point:
put autorelease on object
retain a new string copy
Then there is one more quirk to this and this is where I am getting rather suspicious, namely in the -dealloc method which looks like this:
- (void) dealloc {
[[self wwanServiceId] release];
[super dealloc];
}
So what happens there? it will afaik release the wwanServiceId and as I said the only time it's memory management is being touched (if I haven't missed anything but I feel pretty sure) is to put an autorelease and retain it.
So to summarize:
Is the idea here that he thought that since he always retain a new copy after putting autorelease he need to release it in the end.. or well it's the only thing I can think about. Or just felt it would be safe to do an extra release in the end just in case..?
Because as far as I understand it, if this setter is called one time it will put an autorelease (-1 in future), do a retain (+1) and when destructor is called it will do the "final release" (-1).
Any ideas or suggestions helping me understand (if in fact I am wrong and the memory handling is correct as is) would be appreciated.
You wrote:
Here wwanServiceIdis a NSString member of the class, and to me this seem like a strange way to do it. As far as I understand it would begin by putting an autorelease on the object, basically saying: "whenever this object seem to not be used, release it for me I don't really care" then the copy will up the retain count +1 on.... wwanServiceId? or newValue? I guess the first.
This seems to point to the source of your confusion. wwanServiceId is a variable which can contain a reference to an object of type NSString. Variables do not have reference counts only objects do.
The previous employee wrote:
- (void) setWwanServiceId: (NSString *) newValue {
[wwanServiceId autorelease];
wwanServiceId = [newValue copy];
}
The expression [wwanServiceId autorelease] means: read the reference stored in wwanServiceId and autorelease the object that reference refers to - let's call that object A. Important: This does not delete object A; it will be released as some later stage and if at that time there are no remaining references object A will be deleted.
The expression [newValue copy] means: read the reference stored in newValue, use that to locate the object (call it object B), make a copy of that object to produce a new object (call it object C), and return a reference to the new object. This new object is owned by the caller of copy, so there is no need to retain it.
Finally the assignment stores the reference to object C into wwanServiceId.
So there is a maximum of three distinct objects involved:
A: the original object referenced by wwanServiceId, this is autoreleased to remove the ownership of wwanServiceId.
B: the object referenced by newValue, this is left untouched
C: a newly created copy of B owned through wwanServiceId
Why "autorelease" in the code and "maximum of three distinct" above?
The method could be called with newValue referencing object A, e.g. as in:
[self setWwanServiceId:[self wwanServiceId]]
If this was to occur and (a) release was used instead of autorelease and (b) there was no other reference to object A then the release would delete object A and then when [newValue copy] was evaluated newValue would be referencing a deleted object... The use of autorelease in this case delays the deletion until after the copy.
So what the previous employee wrote is not in any way "wrong", but as some of the other answer suggest it may be an unusual style. Another way you see this written is:
- (void) setWwanServiceId: (NSString *) newValue
{
NSString *oldValue = wwanServiceId;
wwanServiceId = [newValue copy];
[oldValue release];
}
which also ensures any deletion occurs after the copy.
HTH.
To be short and helpful:
This is wrong:
- (void) setWwanServiceId: (NSString *) newValue {
[wwanServiceId autorelease];
wwanServiceId = [newValue copy];
}
This is right:
- (void) setWwanServiceId: (NSString *) newValue {
if (newValue != wwanServiceId) {
[wwanServiceId release];
wwanServiceId = [newValue copy];
}
}
To explain in short:
[wwanServiceId autorelease]; is an unnecessary sent message, because autoreleasing an object will reduce the retain count at some unknown point in the future. And in the next line you are wwanServiceId = [newValue copy]; instantly setting the instance variable. So, in your memory you now have a to be autoreleased object and a new object. One of them is too much The new object is, where the pointer of your IVar is pointing to. The old one is swimming in your Memory Pool with probably no reference to it :-)
Autorelease as few as possible or use ARC.
Oh: And in the dealloc method, please do not send the message like this:
[[self wwanServiceId] release];
Better like this:
[wwanServiceId release];
as Apple recommends to work directly with instance methods in init and dealloc methods, instead of using getters and setters there.
Debug it and have a look.
[wwanServiceId autorelease];
wwanServiceId has an address. This statement does not change it. It does decrement the retain count of this object though.
Thats it.
wwanServiceId = [newValue copy];
This statement creates a new object. The new object is a copy of newValue. Compare the addresses of the objects and you will see, that the address inn wwanServiceId will vary from the address of newValue and it will vary from the address that wwanServiceId did have just before the statement was executed.
The retain, that is implicit in copy will affect wwanServiceId, but it affects the new object, that was just creaed with copy. It does not affect the wwanServiceId object which was autoreleased during the statement before.
At some point after the execution of setWwanServiceId had finished, the old and autoreleased object will dissappear. (Assuming that the retain count is 0 now. If it is >0 because it is still retained for other reasons or just for error, then it will remain and potentially cause a leak.)
Once you understood that you will not question any more what is happening in the dealloc method. wwanServiceId is released. Meaning its retain count is reduced by 1. In the event that it is 0 then it will be deallocated automatically.
You could even autorelease it there too. The diffrerence to autorelease is basically that an autoreleased object is still around and available while the current method is being executed. Its release comes into effect at some later point in time.
But there is no reason for autoreleasing the object in dealloc.
In the example given there is not even a good reason to autorelease the object in the setter setWwanServiceId. You may well release the object directly in both methods.
Assuming wwanServiceId is the private ivar mapped by the getter wwanServiceId and setter setWwanServiceId, I think it is not correct to autorelease the ivar in the setter.
I would have coded the following:
- (void) setWwanServiceId: (NSString *) newValue {
if (newValue != wwanServiceId) {
[wwanServiceId release];
wwanServiceId = [newValue copy];
}
}
What I mean is: it is not necessary to give ownership of your var to the autorelease pool (which it may be drained at the end of the application). Simply release the ivar. If someone is using it, no problem, it will have a strong reference to it. Otherwise it will be deallocated.

Memory leak in stringWithCString

I encounter memory leak with stringWithCString, can anybody find the memory leak in stringWithCstring function?
SomeView *detailViewController = [[SomeView alloc] initWithNibName:#"SomeView" bundle:nil];
detailViewController.test = [NSString stringWithCString:"abc" encoding:UTF8_ENCODING];
the property in SomeView for test variable is
#property (nonatomic,copy) NSString* test;
Is my property declared correctly?
Are you releasing the string in your [SomeView dealloc] method like this:
- (void)dealloc
{
self.test = nil;
[super dealloc];
}
Whatever you use to "detect" the leak, how reliable is that?
Now I've never used properties, but the code above looks pretty correct -- the string should get released. The "stringWithCString:" will autorelease the string anyway, so there's no problem. However, the "copy" in your property seems to indicate that it makes a copy (huh? Surprise!) of the string, and even if I assume that object-type properties are released when the owning object dies -- if the owning object never dies then the copied string will never be released.
Maybe the memory leak detector really meant to say that the copy of that string is never released because you forgot to release the "detailViewController"? That copy would still be in the same source code line, so even if the memory leak detector can give an accurate location but only provides a line number you could be misled...

passing objects from no arc compiled class to arc enabled class?

I ran into this problem while trying to fix a memory leak with the facebook-ios-sdk. How do i handle this situation when passing objects from no arc compiled classe to arc enabled classe?
This is the code inside the non arc compiled Facebook library: (i removed the unnecessary stuff which is not related to the problem) as you can see, result object is not autoreleased or released.
- (void)handleResponseData:(NSData *)data {
NSError* error = nil;
id result = [self parseJsonResponse:data error:&error];
self.error = error;
// Call the defined delegate wich is my AppDelegate didLoad method wich is arc enabled
[_delegate request:self didLoad:result];
}
- (id)parseJsonResponse:(NSData *)data error:(NSError **)error {
SBJSON *jsonParser = [[SBJSON alloc] init];
//gets the object wich leaks or gets overreleased
id result = [jsonParser objectWithString:responseString];
[jsonParser release];
return result;
}
Now if i try to add autorelease to the result object, i am facing a NSZombie when my arc code in my AppDelegate try's to release the object. However if i leave the code like this i'm facing memory leaks whit the result object which gets not released.
am i missing something basic? i can't get my head around this?
Thanx for any advice! Chris
The result returned from -parseJsonResponse:... is autoreleased already (see note at bottom).
Since the name of the -parseJson method doesn't begin with new, alloc, copy or mutableCopy, the compiler assumes that it returns an object with a +0 reference count, meaning it needs to be retained by the calling code if it is to be kept around, and doesn't need to be released if it's not being kept around. That's a long winded way of saying that it should neither leak nor cause a crash in your ARC code as written in your question.
Passing objects between ARC code and manual reference counting code doesn't require any special handling. You just need to make sure that methods' names match their memory management semantics in the non-ARC code. It certainly seems like you've done that in this case, although as you say, you didn't post your complete code.
Note: Presumably, objectWithString: returns an autoreleased object. If it doesn't it, it should (because it doesn't start with alloc, new, copy, mutableCopy).

Leaks reports seemingly unrelated issues

I'm fairly new to Cocoa and Objective-C. Currently I'm developing a fairly basic application to test my knowledge and put some of the stuff I've been reading about into practice. Everything is working, but Leaks reports a number of issues.
None of these leaks seems to be directly applicable to code that I've written (I have read and tried to follow Apple's rules on memory allocation). Currently my project makes use of Garbage Collection and I'm developing on Snow Leopard. Running AnalysisTool finds no issues with my code (aside from a few naming convention warnings).
Currently my application makes use of an NSTableView which I have hooked up to an NSArrayController. Interacting with the NSTableView seems to cause leaks to report issues (actions such as sorting table columns and other standard user interaction). This leads me to believe that my use of the NSArrayController (and my implementation of its content source) is to blame.
Currently the NSArrayController receives its content from an NSMutableArray (timers) handled in my Application's delegate like so:
- (id) init
{
if (self = [super init])
{
timers = [NSMutableArray array];
}
return self;
}
- (void) dealloc
{
[timers release];
[super dealloc];
}
Within Interface Builder my NSArrayController has its Object Controller set to the Timing class, which is defined below:
#interface Timing : NSObject {
NSString *desc;
NSDate *timestamp;
bool active;
}
#end
#implementation Timing
-(id) init
{
if (self = [super init])
{
desc = #"New timing";
timestamp = [[NSDate alloc] init];
active = false;
}
return self;
}
-(void) dealloc
{
[timestamp release];
[super dealloc];
}
#end
I've used standard Cocoa bindings to hook up Add and Remove buttons to manipulate the TableView and these seem to work correctly (clicking Add will create a row in the TableView with the value of 'New timing', for instance).
Leaks reports that the libraries responsible are AppKit and CoreGraphics. Although, honestly, I'm still new to the Leaks tool - so I could be reading its output incorrectly. If it helps, I've placed a screenshot of its output here. If anyone could point me in the right direction, that would really be appreciated.
As an aside, I've also been experimenting with manually adding objects to the timers array without the use of Cocoa bindings. Here's what I came up with:
Timing *timingInstance = [[Timing alloc] init];
[timers addObject:timingInstance];
[timingInstance release];
[timersController setContent:timers];
[timersTableView reloadData];
Again, this seems to work, but I thought it best to ask the experts!
Your memory management for the timers array is not quite correct. Using the array factory method will return an instance of NSMutableArray that has already been autoreleased, so the lifetime of that object is (probably) limited to the end of the current run loop, and it will be over-released when you call release in your dealloc method. The proper way to do it is as follows:
- (id) init
{
if (self = [super init])
{
timers = [[NSMutableArray alloc] initWithCapacity:0];
}
return self;
}
This method will give you an instance of NSMutableArray with a retain count of 1, which will then drop to zero (and properly release the memory) when you call release in your dealloc method. The call to alloc in your init method is balanced out by the call to release in your dealloc method. I notice that this is the exact pattern that you used for your NSDate object in the Timing class, so you are already familiar with the idea.
Your code as written is not leaking. The Cocoa frameworks will sometimes generate false leak reports when run under leaks, as certain things such as singletons and caches which are used in the implementation of the frameworks will sometimes show up as leaks even though they're not.
You're probably better off running the ObjectAlloc and/or ObjectGraph instruments to get an idea of when your objects are being allocated and deallocated.
Currently my project makes use of
Garbage Collection and I'm developing
on Snow Leopard
I don't understand. You're using garbage collection right? If so then GC takes care of releasing objects for you so anywhere you use "release" does absolutely nothing. Release calls are ignored when GC is enabled. You only use release when you're managing the memory yourself which is when GC is off. Also, your dealloc methods do nothing too. In GC that method is never used. When you create an object and then you finish with it you tell GC that it's OK to get rid of the object by setting it to nil. That's all you have to do. There is no "release" needed or dealloc method needed. Just set things to nil or or not as needed.

Set pointers to nil after release?

After releasing objects is it best to set the pointers to nil? Thats what I have been doing, just wanted to ask if its necessary, good practice or overkill?
- (void)dealloc{
[planetName release]; // NSString instance variable
[super dealloc];
}
#end
.
- (void)dealloc{
[planetName release]; // NSString instance variable
planetName = nil;
[super dealloc];
}
#end
cheers -gary-
Depends on the scope of the variable that holds the pointer. I always set pointers to nil if they continue to exist within the scope, just in case I'm calling the variable again somewhere else. Otherwise, there's a risk that I would access a memory location that contained an object which is now released.
But if the variable goes out of scope, then it won't be used either, thus assigning nil to it is a bit overkill. Still, it is a good practice to just assign nil just in case someone else decides to add code to your code and accidently uses the variable again within it's scope but after it was freed.
Usually when programming in C/C++ I set it to null. Why? Because even if you free the memory being pointed, the pointer still holds the address of that freed memory. It can cause a serious access violation problems in code like this:
if(myPointer != null)
{
doSomething(myPointer);
}
If you had set your pointer to null, this will never happen
It's considered good practice. If you set your pointers to nil after releasing them, then in case you misuse your variable at a later point of execution, you'll get a proper error.
At times this can be crucial, as I just found out. I use a camera in my game which keeps a pointer to a generic target. If you return to the main menu from a level then it clears the level from memory but keeps the camera and game layers.
-(void) dealloc {
[target release];
target = nil;
[super dealloc];
}
Since the camera will exist longer than the target, it's best to set target to nil, otherwise when the level loads again and you set a new target:
-(void) setTarget:(CCNode *)aTarget {
[target release];
target = [aTarget retain];
[self update:0];
}
It will crash on that release if the target is junk and not nil. Sending a message to nil is fine, but not to some arbitrary junk memory. That gives me a EXC_BAD_ACCESS.