开发者

How can this Xcode Clang static analyzer warning be suppressed?

"Potential leak of an object allocated on line n and stored into 'variable'."

Normally this is a very helpful analyzer warning, but there are a few situations where I get annoying false positives that I would like to suppress to keep my analyzer results clean. In the analyzer's defense, what it's noticing would definitely be a memory leak were it not for a release in another path of execution (to which it is blind).

I'll ela开发者_如何学运维borate on my situation. It happens in various flavors, but the general pattern is as follows:

  1. An object is allocated and its delegate is set.
  2. Something is done with the object. (A task started, a view displayed, etc).
  3. Execution of current method ends. (Enter Clang warning).
  4. Object decides its task is complete, sends delegate a message.
  5. Delegate releases object.

This is not at all an esoteric design pattern, so I'm hoping suppression is possible. I know it can be avoided by storing the offending object in an ivar that is later released, but I greatly prefer to not add ivar pollution.


Clang has a few new Source Annotations. In specific, you may be interested in the ns_consumed attribute.


I think you should heed the static analyser message in this case. Your pattern has potential problems.

Specifically, when you return from the method invoked to do step 5, you are in a method of an object that may already have been deallocated. I interpret your pattern something like this:

// steps 1, 2, 3
-(void) methodThatCreatesObject
{
    id theObj = [[TheObj alloc] init];
    [theObj setDelegate: delegateObj];
    // other stuff
}

Note the above breaches the memory management rules

// step 4 - a method of theObj
-(void) someMethod
{
    [delegate notifyTaskCompleteFromObj: self];
    // self points to an invalid object here.  Doing anything with self results in EXC_BAD_ACCESS
}

The above breaches an assumption stated in the memory management rules:

A received object is normally guaranteed to remain valid within the method it was received in

if we say self is a received object, which it is technically, since it is passed as a parameter on the stack.

// step 5 the delegate method defined in the delegate object

-(void) notifyTaskCompleteFromObj: (TheObj*) anObj
{
    // do stuff
    [anObj release];
}

The above also breaches the memory management rules.

The normal pattern is to have a controller that owns both the delegate and the object that has the delegate (often the controller is itself the delegate). I think you should move to that pattern.


Another interesting option here occurred to me. The OP gave the following scenario:

  1. An object is allocated and its delegate is set.
  2. Something is done with the object. (A task started, a view displayed, etc).
  3. Execution of current method ends. (Enter Clang warning).
  4. Object decides its task is complete, sends delegate a message.
  5. Delegate releases object.

If, instead of an explicit release, you merely wanted to extend the lifetime of the allocated object to that of the allocating/delegeate object, you could to this:

TheObject* foo = [[TheObject alloc] init] autorelease];
foo.delegate = self;
[foo doSomething];
objc_setAssociatedObject(self, foo, foo, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return;

By setting foo as an associated object with the retain policy, the delegate (self) will effectively take a retain on the object which will be subsequently released whenever the delegate(self) is dealloced (later).

It's not EXACTLY what the OP asked for, but it's a useful pattern nonetheless, and feels like it would probably suffice in the situation the OP presented.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜