有没有可能抑制Xcode 4静态分析器的警告?

41

Xcode 4的静态分析器在我的代码中报告了一些虚假阳性。是否有任何方法可以抑制它们?


2
虽然罕见,但可能会出现误报。请发布您的代码。 - bbum
使用苹果的单例设计模式(参见“Cocoa基础指南”中的“创建单例实例”)分析器会给出“可能泄漏在XX行分配的对象”的警告。 - DreamOfMirrors
5
可以说,依赖于单例的设计值得静态分析器发出警告信息。 :-) - JeremyP
9
这是一个经常被问到的问题。它询问如何逐个禁用警告,而不是如何设计软件或者是否应该避免单例模式。单例模式也不是分析器出现这种情况的唯一情况。在这种情况下,“误报”通常是指分析器认为存在潜在的内存泄漏,但开发人员更清楚因为他/她能比编译器更抽象地思考。 - quickthyme
我有一个(false?not false?)的正面,其中我会得到一个对象,并为稍微修改过的对象调用setObject:forKey:如果我得到一个nil对象,那就是一个错误,所以我只是将nil对象传递给setObject:forKey:它会崩溃。我知道这一点。这就是我想要的,当调用者给我不正确的参数时,我希望崩溃。静态分析器找出了这个问题并进行了投诉。 - gnasher729
显示剩余2条评论
4个回答

72

我找到了一个解决方案:可以通过以下方式避免错误的正向结果(例如,苹果的单例设计模式):

#ifndef __clang_analyzer__

// Code not to be analyzed

#endif

分析器不会分析那些预处理指令之间的代码。


当进行分析时,这会导致代码完全无法编译吗? - CarmeloS
1
__clang_analyzer__是一个宏,当程序被编译为分析器时定义(请参阅Clang用户手册)。 当它被定义时,#ifndef#endif之间的代码不会被编译,这意味着分析器看不到它。但是,当程序未被编译为分析器时,该宏未被定义,代码将像平常一样被编译。 - DreamOfMirrors
有些东西告诉我,如果你删除了代码的某些部分,它可能无法编译。或者你需要在 #else 中添加一个存根。我是对的吗? - RavisMsk
这是一个严重的错误 - 这个预处理条件会使得“不需要分析的代码”在源代码分析时也完全不被编译 - 因此会导致分析后的代码无法正常运行!!!另外,如果你在 #ifndef 中声明了一个变量,那么所有在 #ifndef...#endif 之外的其他代码都将没有这个变量!!! - Motti Shneor

8

请看这个页面,它展示了如何使用多个 #define 注释 Objective-C 方法和参数,以帮助静态分析器 (clang) 做正确的事情。

http://clang-analyzer.llvm.org/annotations.html

从该页面:

Clang前端支持多种源级别注释,以GCC样式的属性和预处理指令的形式,这些注释可以帮助更好地使用Clang静态分析器。这些注释既可以帮助抑制误报,也可以增强分析器发现错误的能力。


1
这些注释似乎比#ifndef __clang_analyzer__更好,因为它们适用于方法在任何地方使用的情况。例如:@property (nonatomic, retain) NSString* newString NS_RETURNS_NOT_RETAINED; - Noah Harrison

6

请看我在这里的回答。您可以为文件添加编译标志,静态分析器将忽略它们。这对于您不关心的第三方代码可能更好,而不适用于您正在编写的一方代码。


0

大多数情况下,像CF_RETURNS_RETAINED这样的东西并遵循“创建”规则对我来说都有效,但我遇到了一个无法抑制的情况。 最终通过查看llvm源代码找到了一种抑制分析器的方法:

https://llvm.org/svn/llvm-project/cfe/trunk/test/ARCMT/objcmt-arc-cf-annotations.m.result

“测试一下当我们存储指向全局变量的指针时是否可以抑制错误。”
static CGLayerRef sSuppressStaticAnalyzer;
static CGLayerRef sDmxImg[2][2][1000]; // a cache of quartz drawings.
CGLayerRef CachedDmxImg(...) // which lives for lifetime of app!
{
    ...

    CGLayerRef img = sDmxImg[isDefault][leadingZeroes][dmxVal];
    if ( !img )
    {
        NSRect imgRect = <some cool rectangle>;

        [NSGraphicsContext saveGraphicsState];
        CGContextRef ctx = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
        CGLayerRef cgLayerRef = CGLayerCreateWithContext(ctx, imgRect.size, NULL);
        CGContextRef layerCtx = CGLayerGetContext(cgLayerRef);
        [NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithGraphicsPort:layerCtx flipped:YES]];

        ... draw some gorgeous expensive Quartz stuff ...

        img = cgLayerRef;
        sDmxImg[isDefault][leadingZeroes][dmxVal] = cgLayerRef;
        sSuppressStaticAnalyzer = cgLayerRef; // suppress static analyzer warning!
        [NSGraphicsContext restoreGraphicsState];
   }
   return img;
}

由于某种原因,给静态数组赋值并没有抑制警告,但是给普通的旧静态'sSuppressStaticAnalyzer'赋值确实做到了。 顺便说一下,使用CGLayerRef上述方法是我发现重新绘制缓存图像最快的方式(除了OpenGL)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接