views:

1722

answers:

3

Running a static analysis with clang in both XCode 3.2 and Nikita Zhuk's Analysis Tool I've often come across this pair of warnings:

Method returns an Objective-C object with a +0 retain count (non-owning reference)

Incorrect decrement of the reference count of an object is not owned at this point by the caller

An example of code that may provoke this warning:

UIButton* button = [[UIButton buttonWithType:UIButtonTypeCustom] initWithFrame: CGRectMake(x, y, width, height)];
return button;

I assumed that buttons created this way are autoreleased, just like any other NSObject created with a convenience factory method. So I return it, and the caller can decide whether to retain it or not. What's the problem with that?

Am I obliged to retain and autorelease the object before returning it? And most importantly, could whatever this warning is warning against ever be the cause of scary release-related crashes?

I realize now that this seems to only occur with UIButtons. Is it due to it being a class cluster?

EDIT: The snipped below shows a minimal case where clang issues these warnings (with the warnings in bold). Both warnings are flagged on the statement creating the object (the buttonWithType: message).

-(UIButton*) ztupidTezt:(UIImage*) img
{
  UIButton* bt = [[UIButton buttonWithType:UIButtonTypeCustom]initWithFrame:

1 Method returns an Objective-C object with a +0 retain count (non-owning reference)

2 Incorrect decrement of the reference count of an object is not owned at this point by the caller

 CGRectMake(0.0f, 0.0f, img.size.width, img.size.height)];
    bt setImage:img forState:UIControlStateNormal];
    return bt;
}
+4  A: 

The cause is most likely the use of sending both a buttonWithType: and initWithFrame: message. init* methods perform tasks that should only be done once for a given object. Class methods that create objects also initialize them. The result of your code is repeated initialization. Instead, send the buttonWithType message, then assign to the frame property.

outis
Makes sense, and I'll follow your advice. But how is what you explained reflected in the warning message emitted by clang? Is there in fact any danger of erroneously decrementing the retain count? I can't say that I've noticed any bugs that seem related to this (but that could of course be because they just passed under my radar).
Felixyz
That requires more knowledge of Clang and Objective-C internals than I possess. If I had to guess, I'd say the "+0 retain count" refers to the call to `buttonWithType:`, and an `init*:` message should only be sent to an owned object, so sending `initWithFrame:` provokes the warnings. Translating, `buttonWithType:` incorrectly decremented the retain count, because `initwithFrame:` requires an owned object.
outis
outis: Close. The `initWithFrame:` message is wrong, but does not factor into either of the analyzer warnings.
Peter Hosey
+9  A: 

Well.... that code makes no sense.

buttonWithType: returns an instance of a UIButton that is already initialized. You shouldn't be calling -initWithFrame: on it.

Call setFrame:.

The bad code is confusing the analyzer.

Secondly, why bother with a third party tool to do the analysis. If you are using Xcode 3.2 on Snow Leopard (you should be -- it is a vastly better version of Xcode than the last release on Leopard), you can just "build and analyze". All of the analysis results will be presented inline with your code quite nicely.

bbum
Thanks. The same additional questions as in my comment to outis apply. "Analyzer confused" is a possible explanation of the unhelpful warning message.Secondly, I still mainly use XCode3.1 because I still mainly use Leopard. And Analysis Tool gives you additional suggestions and warnings (some useful, some perhaps less so) on top of clang's.
Felixyz
I'm not sure the analyzer is confused. `buttonWithType:` returns an autoreleased (+0 retain count) object, which is exactly what the analyzer says is happening. You don't say what statement is getting flag #4; I'm guessing it's a `release` or `autorelease` message that you didn't show us.
Peter Hosey
No, there are no release or autorelease messages. (If there were, I would probably be experiencing frequent crashes.) In the interest of getting the best possible answers here, I do my best to show you all that could be relevant. Please see minimal example case added to original question.
Felixyz
What I'm still wondering is, could this admittedly erroneous piece of code actually ever be the cause of a crash?
Felixyz
Sure-- the behavior of calling -init* on an already initialized object is undefined.
bbum
+1  A: 

Does the method name that has this code within it have "new" as a prefix? The Clang Static Analyzer follows standard Cocoa naming conventions and assumes that a -newSomething method will return an instance with a retain count of 1. If it's seeing an autoreleased object being returned from such a method, it might present the warning you're seeing.

Brad Larson
No it doesn't. Please see added minimal example above.
Felixyz