clang 静态分析器跳过一些检查

clang static analyzer skipping some checks

我正在使用 clang 静态分析器 4.0.0。 对于下面的例子

int fun(){

    int aa = 1,bb = 0;
    int cc = aa/bb; // 1) devide by zero. // Reported by clang

    int *pt = nullptr;
    int a = *pt;    // 2) null pointer dereference. // NOT Reported by clang

    int b;
    int c = a + b;  // 3) Unused initialization. // Reported by clang

    return cc;
}

Clang 静态分析器仅报告两个问题 1 和 3,并跳过问题 2。

而如果我像这样改变问题的顺序

int fun(){

    int *pt = nullptr;
    int a = *pt;    // 1) null pointer dereference. // Reported by clang

    int aa = 1,bb = 0;
    int cc = aa/bb; // 2) devide by zero. // NOT Reported by clang

    int b;
    int c = a + b;  // 3) Unused initialization. // Reported by clang

    return cc;
}

然后 clang 静态分析器报告 1 和 3 并跳过 2。

我是运行 clang static analyzer 使用这个命令

clang-check.exe -analyze D:\testsrc\anothercpp.cpp

这是非常不一致的行为。无论问题的顺序如何,都会跳过其中一个问题。 另外,我用 clang 5.0.1 检查了这个场景,结果相同。

有人知道为什么静态分析器会出现这种情况吗?

提前致谢。

-赫曼特

快速查看代码,您观察到的行为似乎是设计使然。

当可能发现空指针取消引用的 DereferenceChecker 报告错误时,它会创建一个 "error node" 停止对 path-sensitive 的进一步探索分析。

void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
                                   CheckerContext &C) const {
  // Generate an error node.
ExplodedNode *N = C.generateErrorNode(State);

CheckerContext::generateErrorNode documented 停止探索程序中的给定路径。

  /// \brief Generate a transition to a node that will be used to report
  /// an error. This node will be a sink. That is, it will stop exploration of
  /// the given path.
  ///
  /// @param State The state of the generated node.
  /// @param Tag The tag to uniquely identify the creation site. If null,
  ///        the default tag for the checker will be used.
  ExplodedNode *generateErrorNode(ProgramStateRef State = nullptr,
                                  const ProgramPointTag *Tag = nullptr) {
    return generateSink(State, Pred,
                       (Tag ? Tag : Location.getTag()));
}

这是有道理的,因为在像空指针取消引用这样严重的错误之后,无法对程序做出很多有意义的预测。由于空指针取消引用在 C++ 中是 undefined behaviour,因此该标准允许任何事情发生。只有查看程序的细节和它所处的环境 运行,才能做出更多的预测。这些预测可能超出静态分析器的范围。

实际上,您一次只能修复一个错误,并且可能会继续修复错误,直到静态分析器停止提出有效的投诉。

检测未使用的变量不需要进行路径敏感分析。因此,这种类型的检查器仍然有效。

所有这些都表明您不能简单地为静态分析器编写一些原始的人工测试。我在文章“Why I Dislike Synthetic Tests”中详细讨论了这一点。很可能是由于某些内部原因(但肯定不是因为错误),Clang 分析器会跳过 null 取消引用操作之后的代码片段,这显然会导致未定义的行为。或者它可能会因为被零除而跳过。这并没有错。在取消引用 null 或除以零之后写入的内容实际上并不重要:后续代码无论如何都不会执行。所以,这个问题与compiler/analyzer的错误无关,而是像这样粗心地编写测试的结果。为诊断编写好的测试是一项艰巨的工作,这需要您小心并了解许多细微的细节。