menunjukkan "lompatan kondisional atau bergerak tergantung pada nilai valgrind yang tidak diinisialisasi"

166

Jadi saya telah mendapatkan beberapa pesan nilai misterius yang tidak diinisialisasi dari valgrind dan sudah cukup misteri dari mana nilai buruk itu berasal.

Tampaknya valgrind menunjukkan tempat di mana nilai unitialised akhirnya digunakan, tetapi bukan asal dari nilai yang tidak diinisialisasi.

==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)

Seperti yang dapat dilihat, ini menjadi sangat samar .. terutama karena ketika dikatakan oleh Class :: MethodX, kadang-kadang menunjuk langsung ke ostream dll. Mungkin ini karena optimasi?

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

Seperti itu. Apakah ada sesuatu yang saya lewatkan? Apa cara terbaik untuk menangkap nilai buruk tanpa harus menggunakan pekerjaan detektif printf yang sangat lama?

Memperbarui:

Saya menemukan apa yang salah, tetapi anehnya, valgrind tidak melaporkannya ketika nilai buruk pertama kali digunakan. Itu digunakan dalam fungsi multiplikasi:

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

Di mana speedfac adalah pelampung yang disatukan. Namun, pada saat itu tidak dilaporkan dan tidak sampai nilainya dicetak bahwa saya mendapatkan kesalahan .. Apakah ada pengaturan untuk valgrind untuk mengubah perilaku ini?

kamziro
sumber

Jawaban:

230

Gunakan opsi valgrind --track-origins=yesuntuk melacak asal-usul nilai yang tidak diinisialisasi. Ini akan membuatnya lebih lambat dan mengambil lebih banyak memori, tetapi bisa sangat membantu jika Anda perlu melacak asal dari nilai yang tidak diinisialisasi.

Pembaruan: Mengenai titik di mana nilai tidak diinisialisasi dilaporkan, manual valgrind menyatakan :

Penting untuk dipahami bahwa program Anda dapat menyalin data sampah (tidak diinisialisasi) sebanyak yang diinginkan. Memcheck mengamati ini dan melacak data, tetapi tidak mengeluh. Keluhan dikeluarkan hanya ketika program Anda mencoba memanfaatkan data yang tidak diinisialisasi dengan cara yang dapat memengaruhi perilaku program Anda yang terlihat secara eksternal.

Dari FAQ Valgrind :

Mengenai pelaporan salinan dari nilai memori yang tidak diinisialisasi, ini telah disarankan beberapa kali. Sayangnya, hampir semua program secara sah menyalin nilai-nilai memori yang tidak diinisialisasi di sekitar (karena kompiler menyusun struct untuk menjaga penyelarasan) dan ingin memeriksa mengarah ke ratusan positif palsu. Karenanya Memcheck tidak mendukung pemeriksaan yang penuh semangat saat ini.

mark4o
sumber
1
Apa versi minimum valgrind untuk menggunakan fitur ini? Saya menggunakan 3.3.0 dan sepertinya tidak suka opsi.
Robert S. Barnes
8
@Robert: --track-origins ditambahkan dalam valgrind 3.4.0
mark4o
20

Ini artinya Anda mencoba mencetak / mengeluarkan nilai yang setidaknya sebagian tidak diinisialisasi. Bisakah Anda mempersempitnya sehingga Anda tahu persis nilai apa itu? Setelah itu, telusuri kode Anda untuk melihat di mana kode itu diinisialisasi. Kemungkinannya adalah, Anda akan melihat bahwa itu tidak sepenuhnya diinisialisasi.

Jika Anda memerlukan bantuan lebih lanjut, memposting bagian kode sumber yang relevan mungkin memungkinkan seseorang menawarkan lebih banyak panduan.

EDIT

Saya melihat Anda telah menemukan masalah. Perhatikan bahwa valgrind mengawasi lompatan kondisional atau bergerak berdasarkan variabel unitial. Artinya adalah bahwa ia hanya akan memberikan peringatan jika eksekusi program diubah karena nilai yang tidak diinisialisasi (mis. Program mengambil cabang yang berbeda dalam pernyataan if, misalnya). Karena aritmatika yang sebenarnya tidak melibatkan lompatan atau gerakan bersyarat, valgrind tidak memperingatkan Anda tentang itu. Alih-alih, ia menyebarkan status "tidak diinisialisasi" ke hasil pernyataan yang menggunakannya.

Ini mungkin tampak berlawanan dengan intuisi bahwa itu tidak memperingatkan Anda dengan segera, tetapi seperti yang ditunjukkan oleh mark4o , itu melakukan ini karena nilai-nilai yang tidak diinisialisasi digunakan dalam C sepanjang waktu (contoh: bantalan dalam struktur, realloc()panggilan, dll.) Sehingga peringatan itu tidak akan sangat berguna karena frekuensi positif palsu.

RarrRarrRarr
sumber
Terima kasih. Saya baru tahu apa yang salah, tetapi yang aneh adalah, Valgrind tidak melaporkan nilai satuan unitized sampai digunakan di tempat lain ..
kamziro
Itu disengaja. Jika hanya menyalin atau melewati nilai yang tidak diinisialisasi menyebabkan laporan kesalahan maka Anda akan mendapatkannya sepanjang waktu dari padding dalam struktur.
mark4o