Aplikasi Verifier dikombinasikan dengan Alat Debugging untuk Windows adalah pengaturan yang luar biasa. Anda bisa mendapatkan keduanya sebagai bagian dari Kit Pengandar Windows atau Windows SDK yang lebih ringan . (Mengetahui tentang Aplikasi Verifier ketika meneliti pertanyaan sebelumnya tentang masalah korupsi tumpukan .) Saya telah menggunakan BoundsChecker dan Insure ++ (disebutkan dalam jawaban lain) di masa lalu juga, meskipun saya terkejut betapa banyak fungsionalitas dalam Aplikasi Verifier.
Pagar Listrik (alias "efence"), dmalloc , valgrind , dan sebagainya semuanya layak disebutkan, tetapi sebagian besar lebih mudah dijalankan di bawah * nix daripada Windows. Valgrind sangat fleksibel: Saya telah men-debug perangkat lunak server besar dengan banyak masalah tumpukan yang menggunakannya.
Ketika semuanya gagal, Anda dapat memberikan overloads global baru / delete dan malloc / calloc / realloc Anda - cara melakukannya akan sedikit berbeda tergantung pada kompiler dan platform - dan ini akan menjadi investasi yang sedikit - tetapi mungkin terbayar dalam jangka panjang. Daftar fitur yang diinginkan harus terlihat familier dari dmalloc dan electricfence, dan buku yang sangat bagus, Writing Solid Code :
- nilai penjaga : memberikan sedikit lebih banyak ruang sebelum dan setelah setiap alokasi, dengan menghormati persyaratan perataan maksimum; isi dengan angka ajaib (membantu menangkap buffer overflows dan underflow, dan sesekali pointer "liar")
- alokasi isi : isi alokasi baru dengan nilai non-0 ajaib - Visual C ++ sudah akan melakukan ini untuk Anda di Debug build (membantu menangkap penggunaan vars tidak diinisialisasi)
- free fill : isi memori yang dibebaskan dengan nilai non-0 ajaib, yang dirancang untuk memicu segfault jika dalam beberapa kasus dereferenced (membantu menangkap pointer menggantung)
- tertunda gratis : jangan mengembalikan memori yang dibebaskan ke heap untuk sementara waktu, tetap bebaskan isi tetapi tidak tersedia (membantu menangkap lebih banyak petunjuk yang menggantung, menangkap proximate double-frees)
- pelacakan : bisa merekam di mana alokasi dilakukan terkadang dapat bermanfaat
Perhatikan bahwa dalam sistem homebrew lokal kami (untuk target tertanam) kami menjaga pelacakan terpisah dari sebagian besar hal lain, karena overhead run-time jauh lebih tinggi.
Jika Anda tertarik pada lebih banyak alasan untuk membebani fungsi / operator alokasi ini, lihat jawaban saya untuk "Ada alasan untuk membebani operator global yang baru dan hapus?" ; Selain promosi diri yang tak tahu malu, daftar teknik lain yang membantu melacak kesalahan korupsi tumpukan, serta alat-alat lain yang berlaku.
Karena saya terus menemukan jawaban saya sendiri di sini ketika mencari nilai alokasi / gratis / pagar yang digunakan MS, inilah jawaban lain yang mencakup nilai pengisian Microsoft dbgheap .
Anda dapat mendeteksi banyak masalah korupsi tumpukan dengan mengaktifkan Page Heap untuk aplikasi Anda. Untuk melakukan ini, Anda perlu menggunakan gflags.exe yang datang sebagai bagian dari Alat Debugging Untuk Windows
Jalankan Gflags.exe dan dalam opsi file gambar untuk dieksekusi Anda, centang opsi "Aktifkan Penumpukan Halaman".
Sekarang restart exe Anda dan lampirkan ke debugger. Dengan Halaman Tumpukan diaktifkan, aplikasi akan masuk ke debugger setiap kali terjadi tumpukan korupsi.
sumber
Untuk benar-benar memperlambat segalanya dan melakukan banyak pengecekan runtime, coba tambahkan berikut ini di bagian atas
main()
atau yang setara di Microsoft Visual Studio C ++sumber
Artikel yang sangat relevan adalah Debugging Heap corruption dengan Application Verifier dan Debugdiag .
sumber
Melakukan hal-hal nakal dengan ingatan, misalnya menulis setelah ujung buffer, atau menulis ke buffer setelah itu dibebaskan kembali ke tumpukan.
Gunakan instrumen yang menambahkan pemeriksaan batas otomatis ke executable Anda: mis. Valgrind di Unix, atau alat seperti BoundsChecker (Wikipedia menyarankan juga Purify and Insure ++) pada Windows.
Berhati-hatilah karena ini akan memperlambat aplikasi Anda, jadi aplikasi itu mungkin tidak dapat digunakan jika aplikasi Anda adalah soft-real-time.
Alat / alat debugging lain yang mungkin adalah HeapAgent dari MicroQuill.
sumber
Satu tip cepat, yang saya dapatkan dari Mendeteksi akses ke memori yang dibebaskan adalah ini:
sumber
Alat terbaik yang saya temukan bermanfaat dan berfungsi setiap kali adalah ulasan kode (dengan peninjau kode yang baik).
Selain ulasan kode, saya terlebih dahulu akan mencoba Page Heap . Penumpukan Halaman membutuhkan beberapa detik untuk disiapkan dan jika beruntung mungkin akan menunjukkan masalah Anda.
Jika tidak beruntung dengan Page Heap, unduh Debugging Tools untuk Windows dari Microsoft dan pelajari cara menggunakan WinDbg. Maaf tidak bisa memberi Anda bantuan yang lebih spesifik, tetapi men-debug korupsi tumpukan multi-ulir lebih merupakan seni daripada sains. Google untuk "WinDbg tumpukan korupsi" dan Anda harus menemukan banyak artikel tentang hal ini.
sumber
Anda mungkin juga ingin memeriksa untuk melihat apakah Anda menautkan ke perpustakaan runtime C dinamis atau statis. Jika file DLL Anda terhubung dengan perpustakaan runtime C statis, maka file DLL memiliki tumpukan yang terpisah.
Oleh karena itu, jika Anda membuat objek dalam satu DLL dan mencoba untuk membebaskannya di DLL lain, Anda akan mendapatkan pesan yang sama dengan yang Anda lihat di atas. Masalah ini dirujuk dalam pertanyaan Stack Overflow lain, Membebaskan memori yang dialokasikan dalam DLL yang berbeda .
sumber
Apa jenis fungsi alokasi yang Anda gunakan? Baru-baru ini saya menemukan kesalahan serupa menggunakan fungsi alokasi gaya Heap *.
Ternyata saya keliru membuat tumpukan dengan
HEAP_NO_SERIALIZE
opsi. Ini pada dasarnya membuat fungsi Heap berjalan tanpa pengaman thread. Ini merupakan peningkatan kinerja jika digunakan dengan benar tetapi jangan pernah digunakan jika Anda menggunakan HeapAlloc dalam program multi-utas [1]. Saya hanya menyebutkan ini karena posting Anda menyebutkan Anda memiliki aplikasi multi-utas. Jika Anda menggunakan HEAP_NO_SERIALIZE di mana saja, hapus itu dan itu kemungkinan akan memperbaiki masalah Anda.[1] Ada situasi tertentu di mana ini sah, tetapi mengharuskan Anda untuk membuat serialisasi panggilan ke Heap * dan biasanya tidak berlaku untuk program multi-utas.
sumber
Jika kesalahan ini terjadi secara acak, ada kemungkinan besar Anda mengalami balapan data. Silakan, periksa: apakah Anda memodifikasi pointer memori bersama dari utas yang berbeda? Intel Thread Checker dapat membantu mendeteksi masalah tersebut dalam program multithreaded.
sumber
Selain mencari alat, pertimbangkan untuk mencari pelakunya. Apakah ada komponen yang Anda gunakan, mungkin tidak ditulis oleh Anda, yang mungkin tidak dirancang dan diuji untuk berjalan di lingkungan multithread? Atau hanya satu yang Anda tidak tahu telah berjalan di lingkungan seperti itu.
Terakhir kali itu terjadi pada saya, itu adalah paket asli yang telah berhasil digunakan dari pekerjaan batch selama bertahun-tahun. Tetapi ini adalah pertama kalinya di perusahaan ini telah digunakan dari layanan .NET web (yang multithreaded). Itu dia - mereka berbohong tentang kode yang aman.
sumber
Anda dapat menggunakan VC CRT Heap-Check macro untuk _CrtSetDbgFlag : _CRTDBG_CHECK_ALWAYS_DF atau _CRTDBG_CHECK_EVERY_16_DF .. _CRTDBG_CHECK_EVERY_1024_DF .
sumber
Saya ingin menambahkan pengalaman saya. Dalam beberapa hari terakhir, saya memecahkan contoh kesalahan ini dalam aplikasi saya. Dalam kasus khusus saya, kesalahan dalam kode adalah:
Control.Invoke
dan buang benda yang dikelola yang membungkus objek asli yang menjadi milik panggilan balik itu.Control.Invoke
berakhir). Saya harus mengklarifikasi yang saya gunakanboost::thread
, jadi saya menggunakan fungsi anggota sebagai fungsi utas.Control.BeginInvoke
(GUI saya dibuat dengan Winforms) sebagai gantinya sehingga utas asli dapat berakhir sebelum objek dihancurkan (tujuan panggilan balik ini persis memberitahukan bahwa utas berakhir dan objek dapat dihancurkan).sumber
Saya memiliki masalah yang sama - dan itu muncul secara acak. Mungkin ada yang korup dalam membangun file, tetapi saya akhirnya memperbaikinya dengan membersihkan proyek terlebih dahulu kemudian membangun kembali.
Jadi selain tanggapan lain yang diberikan:
Hal-hal macam apa yang dapat menyebabkan kesalahan ini? Sesuatu yang rusak dalam file build.
Bagaimana cara men-debug mereka? Membersihkan proyek dan membangun kembali. Jika sudah diperbaiki, ini kemungkinan masalahnya.
sumber