Saya menulis program C ++ lintas platform untuk Windows dan Unix. Di sisi Window, kode akan mengkompilasi dan mengeksekusi tanpa masalah. Di sisi Unix, itu akan dikompilasi namun ketika saya mencoba menjalankannya, saya mendapatkan kesalahan segmentasi. Firasat awal saya adalah bahwa ada masalah dengan petunjuk.
Apa metodologi yang baik untuk menemukan dan memperbaiki kesalahan kesalahan segmentasi?
sumber
g
dalam konteksCMake
?cmake -DCMAKE_BUILD_TYPE=Debug
.Terkadang kecelakaan itu sendiri bukanlah penyebab sebenarnya dari masalah tersebut - mungkin ingatannya hancur pada titik sebelumnya, tetapi perlu beberapa saat agar korupsi muncul dengan sendirinya. Lihat valgrind , yang memiliki banyak pemeriksaan untuk masalah penunjuk (termasuk pemeriksaan batas array). Ini akan memberi tahu Anda di mana masalahnya dimulai , bukan hanya baris tempat terjadinya crash.
sumber
Sebelum masalah muncul, cobalah untuk menghindarinya sebanyak mungkin:
Gunakan alat yang sesuai untuk debugging. Di Unix:
Dengan GCC Anda juga dapat menggunakan mudflapDengan GCC, Clang dan sejak Oktober percobaan MSVC Anda dapat menggunakan Address / Memory Sanitizer . Itu dapat mendeteksi beberapa kesalahan yang tidak dilakukan Valgrind dan kehilangan kinerja lebih ringan. Ini digunakan dengan mengkompilasi dengan-fsanitize=address
bendera.Akhirnya saya akan merekomendasikan hal-hal biasa. Semakin banyak program Anda dapat dibaca, dipelihara, jelas dan rapi, semakin mudah untuk melakukan debug.
sumber
Di Unix, Anda dapat menggunakan
valgrind
untuk menemukan masalah. Gratis dan bertenaga. Jika Anda lebih suka melakukannya sendiri, Anda dapat membebani operatornew
dandelete
untuk menyiapkan konfigurasi di mana Anda memiliki 1 byte dengan0xDEADBEEF
sebelum dan sesudah setiap objek baru. Kemudian lacak apa yang terjadi di setiap iterasi. Ini bisa gagal untuk menangkap semuanya (Anda bahkan tidak dijamin untuk menyentuh byte tersebut) tetapi ini telah berhasil untuk saya di masa lalu pada platform Windows.sumber
new
dandelete
dapat sangat berguna, penggunaan-fsanitize=address
adalah pilihan yang lebih baik karena kompilator akan mengkompilasi dalam deteksi runtime untuk masalah dan akan membuang memori secara otomatis ke layar yang membuat proses debug lebih mudah.Ya, ada masalah dengan pointer. Sangat mungkin Anda menggunakan salah satu yang tidak diinisialisasi dengan benar, tetapi mungkin juga Anda mengacaukan manajemen memori Anda dengan kebebasan ganda atau semacamnya.
Untuk menghindari pointer yang tidak diinisialisasi sebagai variabel lokal, coba deklarasikannya selambat mungkin, sebaiknya (dan ini tidak selalu memungkinkan) ketika mereka dapat diinisialisasi dengan nilai yang berarti. Yakinkan diri Anda sendiri bahwa mereka akan memiliki nilai sebelum digunakan, dengan memeriksa kodenya. Jika Anda mengalami kesulitan dengan itu, inisialisasi mereka ke konstanta penunjuk nol (biasanya ditulis sebagai
NULL
atau0
) dan periksa.Untuk menghindari pointer yang tidak diinisialisasi sebagai nilai anggota, pastikan mereka diinisialisasi dengan benar di konstruktor, dan ditangani dengan benar di konstruktor salinan dan operator penugasan. Jangan mengandalkan
init
fungsi untuk manajemen memori, meskipun Anda bisa untuk inisialisasi lainnya.Jika kelas Anda tidak memerlukan konstruktor salinan atau operator tugas, Anda dapat mendeklarasikannya sebagai fungsi anggota pribadi dan tidak pernah mendefinisikannya. Itu akan menyebabkan kesalahan kompilator jika mereka digunakan secara eksplisit atau implisit.
Gunakan petunjuk cerdas jika memungkinkan. Keuntungan besar di sini adalah, jika Anda tetap menggunakannya dan menggunakannya secara konsisten, Anda benar-benar dapat menghindari penulisan
delete
dan tidak ada yang akan terhapus ganda.Gunakan string C ++ dan kelas container jika memungkinkan, sebagai ganti string dan array gaya C. Pertimbangkan untuk menggunakan
.at(i)
daripada[i]
, karena itu akan memaksa pemeriksaan batas. Lihat apakah compiler atau library Anda dapat disetel untuk memeriksa batasan[i]
, setidaknya dalam mode debug. Kesalahan segmentasi dapat disebabkan oleh buffer overruns yang menulis sampah di atas pointer yang sangat bagus.Melakukan hal-hal tersebut akan sangat mengurangi kemungkinan kesalahan segmentasi dan masalah memori lainnya. Mereka pasti akan gagal untuk memperbaiki semuanya, dan itulah mengapa Anda harus menggunakan valgrind sekarang dan nanti ketika Anda tidak memiliki masalah, dan valgrind dan gdb ketika Anda melakukannya.
sumber
Saya tidak tahu metodologi apa pun yang digunakan untuk memperbaiki hal-hal seperti ini. Saya tidak berpikir itu akan mungkin untuk muncul dengan salah satu karena masalah yang dihadapi adalah bahwa perilaku program Anda tidak terdefinisi (Saya tidak tahu kasus apa pun ketika SEGFAULT tidak disebabkan oleh semacam UB) .
Ada berbagai macam "metodologi" untuk menghindari masalah sebelum masalah itu muncul. Salah satu yang penting adalah RAII.
Selain itu, Anda hanya perlu membuang energi psikis terbaik Anda padanya.
sumber