Bagaimana cara menentukan kesalahan di dalam kode yang menyebabkan kesalahan segmentasi ?
Bisakah kompiler saya ( gcc
) menunjukkan lokasi kesalahan dalam program?
c++
c
debugging
segmentation-fault
Trilarion
sumber
sumber
Jawaban:
GCC tidak bisa melakukan itu tetapi GDB ( debugger ) pasti bisa. Kompilasi program Anda menggunakan
-g
sakelar, seperti ini:Kemudian gunakan gdb:
Berikut ini adalah tutorial yang bagus untuk memulai dengan GDB.
Di mana segfault terjadi umumnya hanya petunjuk tentang di mana "kesalahan yang menyebabkan" itu dalam kode. Lokasi yang diberikan tidak harus di mana masalahnya berada.
sumber
bt
sebagai singkatan untukbacktrace
.Anda juga dapat
valgrind
mencoba: jika Anda menginstalvalgrind
dan menjalankanmaka itu akan menjalankan program Anda dan menampilkan jejak tumpukan untuk segfault, serta memori yang tidak valid membaca atau menulis dan kebocoran memori. Ini sangat berguna.
sumber
--leak-check=full
tidak akan membantu men-debug segfault. Ini berguna hanya untuk men-debug kebocoran memori.Anda juga bisa menggunakan dump inti dan kemudian memeriksanya dengan gdb. Untuk mendapatkan informasi yang berguna, Anda juga perlu mengkompilasi dengan
-g
bendera.Setiap kali Anda menerima pesan:
file inti ditulis ke direktori Anda saat ini. Dan Anda bisa memeriksanya dengan perintah
File berisi status memori saat program macet. Dump inti dapat berguna selama penyebaran perangkat lunak Anda.
Pastikan sistem Anda tidak menetapkan ukuran file dump inti ke nol. Anda dapat mengaturnya menjadi tidak terbatas dengan:
ulimit -c unlimited
Hati-hati! inti pembuangan bisa menjadi besar.
sumber
Ada sejumlah alat yang tersedia yang membantu men-debug kesalahan segmentasi dan saya ingin menambahkan alat favorit saya ke dalam daftar: Address Sanitizers (sering disingkat ASAN) .
Kompiler modern¹ dilengkapi dengan berguna
-fsanitize=address
flag , menambahkan beberapa waktu kompilasi dan menjalankan overhead waktu yang melakukan lebih banyak pengecekan kesalahan.Menurut dokumentasi cek ini termasuk menangkap kesalahan segmentasi secara default. Keuntungannya di sini adalah Anda mendapatkan jejak stack yang mirip dengan output gdb, tetapi tanpa menjalankan program di dalam debugger. Sebuah contoh:
Outputnya sedikit lebih rumit daripada gdb apa yang akan dihasilkan tetapi ada sisi positifnya:
Tidak perlu mereproduksi masalah untuk menerima jejak tumpukan. Cukup mengaktifkan bendera selama pengembangan sudah cukup.
ASAN menangkap lebih dari sekadar kesalahan segmentasi. Banyak akses di luar batas akan ditangkap bahkan jika area memori itu dapat diakses oleh proses.
¹ Yaitu Dentang 3.1+ dan GCC 4.8+ .
sumber
Jawaban Lucas tentang dump inti adalah baik. Di .cshrc saya, saya punya:
untuk menampilkan jejak balik dengan memasukkan 'inti'. Dan cap tanggal, untuk memastikan saya melihat file yang tepat :(.
Ditambahkan : Jika ada bug korupsi stack , maka backtrace yang diterapkan ke dump inti sering sampah. Dalam hal ini, menjalankan program dalam gdb dapat memberikan hasil yang lebih baik, sesuai jawaban yang diterima (dengan asumsi kesalahan mudah direproduksi). Dan juga waspadai beberapa proses dumping core secara bersamaan; beberapa OS menambahkan PID ke nama file inti.
sumber
ulimit -c unlimited
untuk mengaktifkan dump inti di tempat pertama.Semua jawaban di atas adalah benar dan direkomendasikan; jawaban ini dimaksudkan hanya sebagai upaya terakhir jika tidak ada pendekatan yang disebutkan di atas yang dapat digunakan.
Jika semuanya gagal, Anda selalu dapat mengkompilasi ulang program Anda dengan berbagai pernyataan debug-cetak sementara (mis
fprintf(stderr, "CHECKPOINT REACHED @ %s:%i\n", __FILE__, __LINE__);
) Yang disebarkan sepanjang apa yang Anda yakini sebagai bagian yang relevan dari kode Anda. Kemudian jalankan program, dan amati apa yang terakhir dicetak-cetak dicetak tepat sebelum crash terjadi - Anda tahu program Anda sejauh itu, jadi pasti crash terjadi setelah titik itu. Tambahkan atau hapus debug-cetakan, kompilasi ulang, dan jalankan tes lagi, sampai Anda mempersempitnya menjadi satu baris kode. Pada titik itu Anda dapat memperbaiki bug dan menghapus semua cetakan debug sementara.Ini cukup membosankan, tetapi memiliki keuntungan untuk bekerja di mana saja - satu-satunya waktu yang mungkin tidak adalah jika Anda tidak memiliki akses ke stdout atau stderr karena alasan tertentu, atau jika bug yang Anda coba perbaiki adalah balapan -kondisi yang perilakunya berubah ketika waktu program berubah (karena debug-cetakan akan memperlambat program dan mengubah waktunya)
sumber