下面的两种方法都会分配一个NSString并将其泄漏。运行XCode(4.6)Anaylzer成功标记bar2中的泄漏,但在bar1中没有提到它。
我不承认为什么。
在我的真实项目中,我们发现了一个泄漏,我们希望以一种明显的方式捕获,如bar2中的那个,但由于bar1中的相同行为而找不到它。
请帮我理解原因。谢谢!
-(void)bar1
{
NSString* foo = [[NSString alloc] initWithString:@"foo"];
NSLog(@"%@", foo);
for (int i=0; i<4; i++) {
}
}
-(void)bar2
{
NSString* foo = [[NSString alloc] initWithString:@"foo"];
NSLog(@"%@", foo);
}
有些人提到静态字符串案例是“过度设计”。这个不太做作的例子显示了相同的行为:
-(void)bar1
{
NSString* foo = [[NSString alloc] initWithFormat:@"%d",rand()];
NSLog(@"%@", foo);
for (int i=0; i<4; i++) {
}
}
-(void)bar2
{
NSString* foo = [[NSString alloc] initWithFormat:@"%d",rand()];
NSLog(@"%@", foo);
}
感谢那些指出迭代次数有影响的人。有3,它报告泄漏,4没有。这是一个没有死代码的新示例,只有迭代的差异:
报告泄漏:
-(void)bar1
{
int i=0;
while (i<3) {
i++;
}
NSString* foo = [[NSString alloc] initWithFormat:@"%d",i];
NSLog(@"%@", foo);
}
没有报告泄漏:
-(void)bar2
{
int i=0;
while (i<4) {
i++;
}
NSString* foo = [[NSString alloc] initWithFormat:@"%d",i];
NSLog(@"%@", foo);
}
我已经开通了Apple的DTS门票,我认为这个精致的例子清楚地表明这是分析器中的一个错误。
DTS让我打开它作为我https://bugreport.apple.com的错误。这是问题ID 13491388.
2013年3月29日更新: Apple报告我的错误13491388是错误的错误11486907。 但是,我无法打开或阅读有关错误11486907的任何内容,因此信息完全没用。
Apple开发人员支持FAIL: - (
答案 0 :(得分:3)
Clang的静态分析器似乎是基于控制流:报告总是“如果你遵循这个代码路径,就会发生这件坏事”。我最好的猜测是,SA的不同位之间存在不良的相互作用:
i
仍然小于4),所以它放弃了。我怀疑减少迭代次数会导致检测到泄漏。
如果优化器在NSLog()
返回后确定变量已死并且将此信息用于SA,则启用优化的分析(我认为Xcode支持,如果您编辑方案)可能会给出不同的结果。
你可能还能够调整报告问题时的保守程度(通过命令行选项,或直接从命令行运行clang?),但如果没有标记很多错误,这可能很难做到阳性。
静态分析也不能替代使用Leaks等泄漏检查器。
答案 1 :(得分:3)
另一个答案是正确的;我想为后代提供更多细节。
检漏仪实际 注意到此泄漏。问题是泄漏被认为是低重要性的分析器结果,并且如果泄漏结束后的每个路径都在“接收器”(基本上是分析的异常终止),则不报告泄漏。这是为了防止嘈杂或误报泄漏报告;例如:
NSString *foo = [[NSString alloc] initWithString:@"foo"];
if (SOME_CONDITION) {
NSLog(@"OH NO!");
exit(-1);
} else {
[foo release];
}
这会产生泄漏报告,因为如果条件的计算结果为true,但在exit
运行之前,则会出现泄漏报告,因为foo不再被引用但仍然拥有。 (此代码看起来很奇怪,但正常断言也会触发完全相同的误报。)通过抑制(始终)导致接收器的路径泄漏,此处不会产生误报。
不幸的是,当分析仪放弃时,经历一个“太多”循环也会产生一个接收器。这由命令行参数-analyzer-max-loop
控制;如果您通过-analyzer-max-loop 5
,那么您将获得包含示例代码的泄漏报告。
这也解释了为什么使用像rand()
而不是4
这样的东西;在探索程序状态时,分析器会考虑我们不经历一次,两次,三次等循环的情况。任何更高的循环计数都会导致接收器,但是因为不是所有路径通过水槽,你仍然得到泄漏报告。 (即分析器第一次看到i < rand()
为假的路径,我们离开该功能,因此报告泄漏。)