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


166

したがって、valgrindからいくつかの不思議な初期化されていない値のメッセージを受け取っており、それは悪い値がどこから発生したのかという非常に謎です。

valgrindは、単一化された値が最終的に使用される場所を示しているようですが、初期化されていない値の原点は示していません。

==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がこの動作を変更するための設定はありますか?

回答:


230

valgrindオプション--track-origins=yesを使用して、初期化されていない値の原点を追跡します。これにより、速度が遅くなり、より多くのメモリが必要になりますが、初期化されていない値の原点を追跡する必要がある場合に非常に役立ちます。

更新:初期化されていない値が報告されるポイントに関して、valgrindマニュアルは次のように述べています

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

Valgrind FAQから:

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


1
この機能を使用するための最小のvalgrindバージョンは何ですか?3.3.0を使用していますが、オプションが気に入らないようです。
ロバートS.バーンズ

8
@Robert:--track-originsはvalgrind 3.4.0で追加されました
mark4o

20

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

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

編集

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

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


ありがとう。..私はちょうど間違っていたものを見つけましたが、奇妙なことがあり、それが他の場所で使用されるまで、valgrindのはunitialised値の事を報告しなかった
kamziro

それは意図的なものです。初期化されていない値をコピーまたは渡すだけでエラーレポートが発生した場合は、構造体のパディングから常にそれらを取得します。
mark4o
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.