web-dev-qa-db-ja.com

「条件付きのジャンプまたは移動は初期化されていない値に依存する」valgrindメッセージを特定する

だから私はvalgrindからいくつかの神秘的な初期化されていない値のメッセージを受け取ってきましたが、それは悪い値がどこから生じたのかについてかなり謎です。

Valgrindは、初期化された値が最終的に使用される場所を示しますが、初期化されていない値のOriginは示していないようです。

==11366== Conditional jump or move depends on uninitialised value(s)
==11366==    at 0x43CAE4F: __printf_fp (in /lib/tls/i686/cmov/libc-2.7.so)
==11366==    by 0x43C6563: vfprintf (in /lib/tls/i686/cmov/libc-2.7.so)
==11366==    by 0x43EAC03: vsnprintf (in /lib/tls/i686/cmov/libc-2.7.so)
==11366==    by 0x42D475B: (within /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x42E2C9B: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_float<double>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, char, double) const (in /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x42E31B4: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, double) const (in /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x42EE56F: std::ostream& std::ostream::_M_insert<double>(double) (in /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x81109ED: Snake::SnakeBody::syncBodyPos() (ostream:221)
==11366==    by 0x810B9F1: Snake::Snake::update() (snake.cpp:257)
==11366==    by 0x81113C1: SnakeApp::updateState() (snakeapp.cpp:224)
==11366==    by 0x8120351: RoenGL::updateState() (roengl.cpp:1180)
==11366==    by 0x81E87D9: Roensachs::update() (rs.cpp:321)

見られるように、それは非常に不可解になります。特にClass :: MethodXで言っているとき、それが時々ostreamなどをまっすぐに指しているので。

==11366==    by 0x81109ED: Snake::SnakeBody::syncBodyPos() (ostream:221)

そのように。私が見逃しているものはありますか?超長いprintf探偵の仕事に頼ることなく悪い値をキャッチする最良の方法は何ですか?

更新:

何が間違っていたかを見つけましたが、奇妙なことは、valgrindは最初に悪い値が使用されたときにそれを報告しなかったことです。乗算関数で使用されました:

movespeed = stat.speedfactor * speedfac * currentbendfactor.val;

Speedfacは単一化されたフロートでした。ただし、その時点では報告されず、値が出力されるまでエラーが発生しませんでした。この動作を変更するためのvalgrindの設定はありますか?

154
kamziro

Valgrindオプション --track-origins=yes を使用して、初期化されていない値の発生元を追跡します。これにより、処理が遅くなり、メモリが消費されますが、初期化されていない値の発生元を追跡する必要がある場合に非常に役立ちます。

更新:初期化されていない値が報告されるポイントに関して、 valgrind手動状態

プログラムはジャンク(初期化されていない)データを好きなだけコピーできることを理解することが重要です。 Memcheckはこれを観察し、データを追跡しますが、文句を言いません。苦情は、プログラムが初期化されていないデータを、プログラムの外部から見える動作に影響を及ぼす可能性のある方法で利用しようとする場合にのみ発行されます。

Valgrind FAQ から:

初期化されていないメモリ値のコピーの熱心な報告に関しては、これが複数回提案されています。残念ながら、ほとんどすべてのプログラムは、初期化されていないメモリ値を合法的にコピーします(コンパイラーは構造体をパディングしてアライメントを維持するため)。したがって、Memcheckは現時点では積極的なチェックをサポートしていません。

219
mark4o

これは、少なくとも部分的に初期化されていない値を出力または出力しようとしていることを意味します。値を正確に把握できるように絞り込めますか?その後、コードをトレースして、どこで初期化されているかを確認します。おそらく、完全に初期化されていないことがわかります。

さらにサポートが必要な場合は、ソースコードの関連セクションを投稿すると、誰かがさらにガイダンスを提供できる場合があります。

編集

問題が見つかったようです。 valgrindは、条件付きジャンプまたは移動を監視し、ユニタライズされた変数に基づいていることに注意してください。つまり、初期化されていない値が原因でプログラムの実行が変更された場合にのみ警告が出されます(つまり、プログラムはifステートメントで別のブランチを使用します)。実際の算術には条件付きのジャンプや移動は含まれていないため、valgrindはそのことを警告しませんでした。代わりに、「初期化されていない」ステータスを、それを使用したステートメントの結果に伝播しました。

すぐに警告しないのは直観に反しているように見えるかもしれませんが、mark4oが指摘するように、初期化されていない値が常にCで使用されるため、これを行います(例:構造体のパディング、realloc()呼び出しなど) 。)そのため、これらの警告は、偽陽性の頻度のためにあまり有用ではありません。

20
RarrRarrRarr