clang
does not perform any inter-procedure analysis, at least not yet. Even if it did, it might not necessarily catch this "error"- the permutations of potential code paths tends to rise super exponentially, making it a practical impossibility.
clang
works with a set of heuristics that work "most of the time". Thankfully, Cocoa memory management rules tend to be fairly uniform, so the heuristics work for most uses. The specific example that you've given isn't really covered by the memory management rules, but I think most people (which includes myself) would tend to classify your example as "You've documented via the API that the caller of leaker()
is responsible for release
ing the returned object". This is essentially analogous to - (NSString *)init...
style methods.
clang
knows that methods that begin with init...
return an 'unreleased' object, and it is the callers responsibility to ensure that it is properly released. This forms part of the core of the heuristics- it doesn't need whole program or inter-procedural analysis to do the bulk of reference count checking- if a local block of code gets an object via an init...
method, that local block of code needs to make sure it is properly released
. Naturally, if the local block of code, and the object in question, is part of an init...
method itself, it is covered by the same "rule", so it gets an exception.
What you probably want is something like:
NSString* leaker() __attribute__((ns_returns_retained))
{
return [[NSString alloc] init];
}
This lets the analyzer know that leaker()
returns a 'retained' object, that the caller is responsible for properly releasing it. Although I haven't tested this, I strongly suspect that the 'leak' would be detected at the point where leaker()
is called, i.e.:
void test(void)
{
NSString *leaked = leaker();
// Previous line should be caught as a "leak" by clang.
}
This is one of the unfortunate limitations of any static analyzer, not just clang
.