XCode(4.6)分析仪 - 为什么在一种情况下检测到泄漏而不是另一种?
下面的两个方法都分配一个NSString并将其泄漏。运行XCode(4.6)Anaylzer成功标记bar2中的泄漏,但在bar1中没有提及它。XCode(4.6)分析仪 - 为什么在一种情况下检测到泄漏而不是另一种?
我不知道为什么。
在我的实际项目中,我们发现,我们希望在像在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);
}
我已经开了DTS门票与苹果,作为这个精致的例子,在我看来,清楚地表明,这是一个分析仪的错误。
DTS要求我打开它与https://bugreport.apple.com至极我做了一个错误。这是问题编号13491388.
更新2013年3月29日:苹果 报告说我的错误13491388是错误的欺骗11486907. 但是,我不能打开或阅读错误11486907东西,这样的信息是完全无用的。
苹果开发者支持失败:-(
锵的静态分析似乎是基于控制流:该报告始终是“如果你按照这个代码路径,这种不好的事情发生”我最好的猜测是,它的SA的不同位之间的不必要的相互作用:
- 检漏仪可能只注意到当变量旁边写着或函数返回的泄漏
- 有它多少次经过的限制循环(避免永久搜索)— ch重复两次迭代应该足以检测大多数循环错误。
- 在它击中迭代极限点,静态分析“知道”,它不会退出循环,但(因为
i
仍低于4),所以它放弃。
我怀疑减少迭代次数使待检测的泄漏。
如果优化器确定变量在NSLog()
返回并将此信息用于SA后确定变量已死,则启用优化时执行分析(我认为Xcode支持如果编辑该方案)可能会给出不同的结果。
当报告问题(通过命令行选项,或直接从命令行运行clang?)时,您可能还会调整它的保守程度吗?但是,如果没有标记很多问题误报。
静态分析也没有用于使用泄漏检查等泄漏的替代品。
将“分析”配置设置为“发布”并没有什么区别。如果将迭代计数减少到3,实际上检测到泄漏,但是如果迭代计数未知('for(int i = 0; i
@MartinR如果迭代计数未知,那么*可能*为0(或1或2);我怀疑在报告的“可能的泄漏”中它是0。我不确定Clang是否会尝试一些边缘案例返回值或更复杂的东西。 – 2013-03-18 13:25:30
对方回答是正确的轨道上;我想为后人提供更多的细节。
检漏仪实际上确实通知此泄漏。问题在于泄漏被认为是重要性低的分析仪结果,并且如果泄漏之后的每个路径结束于“汇”(基本上,分析的异常终止),则不会报告泄漏。这是为了防止嘈杂或假阳性泄漏报告;例如:
NSString *foo = [[NSString alloc] initWithString:@"foo"];
if (SOME_CONDITION) {
NSLog(@"OH NO!");
exit(-1);
} else {
[foo release];
}
这将产生泄漏报告,因为如果条件计算为真,但在此之前exit
运行,就不会有泄漏报告,因为富不再被引用,但仍拥有。 (这段代码看起来很奇怪,但正常的断言也会触发完全相同的误报。)通过抑制(总是)导致汇的路径的泄漏,这里不会产生误报。
不幸的是,通过一个循环去“太多”时间也产生下沉时,分析仪放弃。这由命令行参数-analyzer-max-loop
控制;如果您通过-analyzer-max-loop 5
,那么您将通过示例代码获得泄漏报告。
这也解释了为什么使用类似rand()
而非4
作品;探索程序状态时,分析仪认为,我们通过循环没有时间,一次,两次,三次,等任何更高的循环计数导致汇去的情况,但因为没有所有路径经过水槽,你仍然得到泄漏报告。 (即分析器首次看到i < rand()
错误的路径,我们离开该功能,因此报告泄漏)。
在Xcode 4.6上,分析器使用警告'Using initWithString:with literal'标记代码多余的“,但没有提到任何泄漏。如果启用ARC,我不会看到任何泄漏。 – 2013-03-15 20:00:26
在该项目中,ARC被禁用。 – 2013-03-15 20:22:42
另外,是的,这里使用initWithString是愚蠢的,但它只是一个人为的例子。另一个使用init的alloc显示了同样的问题。 – 2013-03-15 20:23:20