CLANG++ 3.3静态分析仪,如何摆脱误报

clang++ 3.3 static analyser, how to get rid of a false positive?

本文关键字:何摆脱 分析仪 静态 静态分析 CLANG++      更新时间:2023-10-16

我一直在我的各种项目上运行clang 3.3的静态分析器。除了一些是我自己的错的问题(这是意料之中的,否则我会非常悲伤和非常自鸣得意),除了以下关于std::function的移动构造函数的问题是一个误报。

在进一步讨论之前,这里有一个简单的测试用例:

int main() {
  std::function<void ()> f1;
  std::function<void ()> f2 = std::move(f1);
}

通过clang++ -std=c++11 --analyze -Xanalyzer -analyzer-output=text foo.cpp运行它(它使用 GCC 的 libstdc++ - 即 4.8.1 版本 - 而不是 clanglibc++),你会得到以下跟踪:

In file included from foo.cpp:1:
In file included from /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/iostream:39:
In file included from /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/ostream:38:
In file included from /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/ios:40:
In file included from /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/char_traits.h:39:
In file included from /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_algobase.h:64:
In file included from /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_pair.h:59:
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/move.h:175:7: warning: Assigned value is garbage or undefined
      _Tp __tmp = _GLIBCXX_MOVE(__a);
      ^~~~~~~~~   ~~~~~~~~~~~~~~~~~~
foo.cpp:30:31: note: Calling move constructor for 'function'
  std::function<void ()> f2 = std::move(f1);
                              ^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2232:2: note: Calling 'function::swap'
        __x.swap(*this);
        ^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2359:2: note: Calling 'swap'
        std::swap(_M_invoker, __x._M_invoker);
        ^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/move.h:175:19: note: Calling 'move'
      _Tp __tmp = _GLIBCXX_MOVE(__a);
                  ^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/move.h:142:30: note: expanded from macro '_GLIBCXX_MOVE'
#define _GLIBCXX_MOVE(__val) std::move(__val)
                             ^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/move.h:175:19: note: Returning from 'move'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/move.h:142:30: note: expanded from macro '_GLIBCXX_MOVE'
#define _GLIBCXX_MOVE(__val) std::move(__val)
                             ^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/move.h:175:7: note: Assigned value is garbage or undefined
      _Tp __tmp = _GLIBCXX_MOVE(__a);
      ^
1 warning generated.

如您所见,移动构造函数std::function(std::function&&)是按照swap实现的。整个操作的步骤是(如果我们相信clang):

  • f1结构正确
  • f2尚未构建,因此包含垃圾
  • f1被搬进了f2,但实际上它真的是一个swap
  • f2现在包含旧f1,但f1包含旧f2,即垃圾
  • 在某些时候,包含垃圾的f1被破坏了......那怎么办呢?

理论说,这是非常糟糕的。在实践中,查看实现,似乎std::function私下继承自_Function_base,后者负责初始化所有重要内容(即。 _M_manager ) 为 null,因此clang关于_M_invoker的警告毫无意义。

以防万一有人怀疑,移动对象应该使其处于不确定状态,您只能分配给它或破坏它。GCC 的 function 实现正是这样做的:就资源管理而言,只有_M_manager是重要的,其余的(包括_M_invoker)只是"方便"的指针。

我在GCC的function实施中挖掘了足够多的东西,对clang诊断的误报状态完全毫无疑问。但是,由于我的代码中有数百个地方发生这种情况,因此至少可以说,浏览静态分析器的结果非常痛苦。

我如何指示clang不要报告此问题?

同样,如果您错过了它,我将clang 3.3与GCC的libstdc++ 4.8.1一起使用。


注意:如果您正在运行clang 3.4构建,并且它没有触发此误报,请告诉我。就我所尝试的而言,我还不能让 3.4 在我的系统上运行(Debian Jessie),但如果它解决了这个问题,我会更加努力。

这可能对你来说很有趣:分析仪的未来发展方向

基本上,您目前只能禁用每个TU或使用的某些检查器

#ifndef __clang_analyzer__
...
#endif

如果你真的需要。但当然应该报告实际的误报。