4

私は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.

ご覧のとおり、move コンストラクターstd::function(std::function&&)は の観点から実装されていswapます。操作全体の手順は次のとおりです (信じるならclang):

  • f1正しく構築されている
  • f2まだ構築されていないため、ガベージが含まれています
  • f1に移動されf2ますが、実際にはswap
  • f2古い ie が含まれるようになりましたが、古いief1が含まれています。ごみf1f2
  • ある時点で、f1含まれているゴミが破壊されます...その後どうなりますか?

理論によれば、これは非常に悪いことです。実際には、実装を見ると、which は重要なもの (つまり) をすべて nullに初期化するように注意してstd::function継承しているように見えるため、 に関する警告は無意味です。_Function_base_M_managerclang_M_invoker

誰かが疑問に思っている場合に備えて、オブジェクトを移動すると、オブジェクトを不確定な状態のままにすることになっています。GCC のfunction実装はまさにそれを行います。_M_managerリソース管理が関係する限り、 のみが重要であり、残り ( を含む_M_invoker) は単なる「便利な」ポインターです。

私は GCC の実装を十分に掘り下げて、の診断の誤検知function状態についてまったく疑いの余地がないようにしました。しかし、コード内で文字通り何百もの場所でこれが発生するため、静的アナライザーの結果を調べるのは控えめに言っても非常に面倒です。clang

clangこの問題を報告しないように指示するにはどうすればよいですか?

繰り返しますが、見逃した場合に備えて、私はclang 3.3GCC と一緒に使用していlibstdc++ 4.8.1ます。


注:clang 3.4ビルドを実行していて、この誤検知がトリガーされない場合は、お知らせください。私が試した限りでは、私のシステム (Debian Jessie) で 3.4 を実行することはまだできませんでしたが、この問題が解決されるのであれば、もっと頑張ろうと思います。

4

1 に答える 1

0

これはあなたにとって興味深いかもしれません: アナライザーの将来の方向性

基本的に、現在、TU ごとに特定のチェッカーのみを無効にするか、使用することができます

#ifndef __clang_analyzer__
...
#endif

本当に必要な場合。もちろん、実際の誤検知は報告する必要があります。

于 2014-02-21T21:30:17.693 に答える