190

そのため、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の設定はありますか?

4

2 に答える 2

262

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

更新:初期化されていない値が報告される時点に関して、valgrind のマニュアルには次のように記載されています。

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

Valgrind FAQから:

初期化されていないメモリ値のコピーの熱心なレポートに関しては、これは何度も提案されています。残念ながら、ほとんどすべてのプログラムは、初期化されていないメモリ値を合法的にコピーし (コンパイラが配列を維持するために構造体をパディングするため)、熱心なチェックにより、何百もの誤検知が発生します。そのため、現時点では Memcheck は熱心なチェックをサポートしていません。

于 2010-04-10T06:40:49.030 に答える
25

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

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

編集

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

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

于 2010-04-10T06:14:03.380 に答える