clang ++ 3.3静态分析器,如何摆脱误报?

时间:2013-10-19 22:19:14

标签: c++ c++11 static-analysis clang++ false-positive

我一直在我的各个项目上运行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版本 - 而非clang的{​​{1}}),您将获得以下跟踪:

libc++

如您所见,移动构造函数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 ie。垃圾
  • 在某些时候,包含垃圾的f2被破坏......那么会发生什么?

理论上说,这非常糟糕。在实践中,查看实现时,f1私有地继承自std::function,它会将所有重要事项(即_Function_base)初始化为null,因此_M_manager关于clang的警告毫无意义。

万一有人怀疑,移动一个对象应该让它处于一个不确定的状态,你只能分配它或破坏它。 GCC的_M_invoker实现正是如此:只有资源管理才涉及function,其余的(包括_M_manager)只是“便利”指针。

我在GCC的_M_invoker实施中挖得足够远,对function诊断的误报的状态完全毫无疑问。但是,由于我的代码中有数百个地方发生这种情况,这使得通过静态分析器的结果至少可以说是非常痛苦。

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

同样,如果你错过了,我正在使用clang和GCC的clang 3.3


注意:如果您正在运行libstdc++ 4.8.1版本,如果则不会触发此误报,请告知我们。据我所知,我无法在我的系统上运行3.4(Debian Jessie),但如果它解决了这个问题,我会更加努力。

1 个答案:

答案 0 :(得分:0)

这可能对您有意义: Future directions for the analyzer

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

#ifndef __clang_analyzer__
...
#endif

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