私は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
。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.
ご覧のとおり、move コンストラクターstd::function(std::function&&)
は の観点から実装されていswap
ます。操作全体の手順は次のとおりです (信じるならclang
):
f1
正しく構築されているf2
まだ構築されていないため、ガベージが含まれていますf1
に移動されf2
ますが、実際にはswap
f2
古い ie が含まれるようになりましたが、古いief1
が含まれています。ごみf1
f2
- ある時点で、
f1
含まれているゴミが破壊されます...その後どうなりますか?
理論によれば、これは非常に悪いことです。実際には、実装を見ると、which は重要なもの (つまり) をすべて nullに初期化するように注意してstd::function
継承しているように見えるため、 に関する警告は無意味です。_Function_base
_M_manager
clang
_M_invoker
誰かが疑問に思っている場合に備えて、オブジェクトを移動すると、オブジェクトを不確定な状態のままにすることになっています。GCC のfunction
実装はまさにそれを行います。_M_manager
リソース管理が関係する限り、 のみが重要であり、残り ( を含む_M_invoker
) は単なる「便利な」ポインターです。
私は GCC の実装を十分に掘り下げて、の診断の誤検知のfunction
状態についてまったく疑いの余地がないようにしました。しかし、コード内で文字通り何百もの場所でこれが発生するため、静的アナライザーの結果を調べるのは控えめに言っても非常に面倒です。clang
clang
この問題を報告しないように指示するにはどうすればよいですか?
繰り返しますが、見逃した場合に備えて、私はclang 3.3
GCC と一緒に使用していlibstdc++ 4.8.1
ます。
注:clang 3.4
ビルドを実行していて、この誤検知がトリガーされない場合は、お知らせください。私が試した限りでは、私のシステム (Debian Jessie) で 3.4 を実行することはまだできませんでしたが、この問題が解決されるのであれば、もっと頑張ろうと思います。