0

它不关心这个:

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;
}

这对我来说似乎特别弱。它只在本地范围内分析吗?如果该工具无法识别这样的事情,我怎么能期望它能够识别我可能犯的实际错误?

4

1 回答 1

4

clang不执行任何过程间分析,至少现在还没有。即使这样做了,它也不一定能捕捉到这个“错误”——潜在代码路径的排列往往会呈指数级上升,这使得它实际上是不可能的。

clang使用一组“大部分时间”有效的启发式方法。值得庆幸的是,Cocoa 内存管理规则往往是相当统一的,因此启发式方法适用于大多数用途。您给出的具体示例并未真正包含在内存管理规则中,但我认为大多数人(包括我自己)倾向于将您的示例归类为“您已通过调用者leaker()负责的 API 记录for releaseing 返回的对象”。这本质上类似于- (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.
}

这是任何静态分析器的不幸限制之一,而不仅仅是clang.

于 2010-04-29T22:21:54.587 回答