它并不关心这个:
NSString* leaker()
{
return [[NSString alloc] init];
}
我认为检查是否有任何代码路径可以调用该函数而不释放其返回值(我通常不会这样编码,我只是测试分析器)。
它将此报告为泄漏:
NSString* leaker()
{
NSString* s = [[NSString alloc] init];
[s retain];
return s;
}
但不是这样:
NSString* leaker()
{
NSString* s = [[NSString alloc] init];
// [s retain];
return s;
}
对我来说似乎特别弱。它只在当地范围内进行分析吗?如果该工具无法接受这样的事情,我怎么能指望它能够发现我可能犯的实际错误呢?
答案 0 :(得分:4)
clang
不会执行任何过程间分析,至少现在还没有。即使它确实如此,它也可能不一定能够捕获这个“错误” - 潜在代码路径的排列趋向于以指数方式上升,使其成为一种实际的不可能性。
clang
使用一组“大部分时间都有效”的启发式方法。值得庆幸的是,Cocoa内存管理规则往往相当统一,因此启发式方法适用于大多数用途。您给出的具体示例并未真正涵盖在内存管理规则中,但我认为大多数人(包括我自己)都倾向于将您的示例归类为“您通过API记录了{{{ 1}}负责leaker()
返回的对象“。这基本上类似于release
样式方法。
- (NSString *)init...
知道以clang
开头的方法会返回一个“未释放”的对象,并且调用者有责任确保它被正确释放。这构成了启发式核心的一部分 - 它不需要整个程序或程序间分析来进行大量的引用计数检查 - 如果本地代码块通过init...
方法获取对象,本地代码块需要确保它正确init...
。当然,如果本地代码块和相关对象是released
方法本身的一部分,它将被相同的“规则”覆盖,因此它会出现异常。
你可能想要的是:
init...
这使分析器知道NSString* leaker() __attribute__((ns_returns_retained))
{
return [[NSString alloc] init];
}
返回一个'保留'对象,调用者负责正确释放它。虽然我没有对此进行测试,但我强烈怀疑在leaker()
被调用时会检测到“泄漏”,即:
leaker()
这是任何静态分析器的不幸限制之一,而不仅仅是void test(void)
{
NSString *leaked = leaker();
// Previous line should be caught as a "leak" by clang.
}
。