[Powered by Google Translate] [Valgrind] [Nate Hardison, Universiti Harvard] Ini adalah CS50, CS50.TV] Beberapa bug yang paling sukar dalam program C datang dari penyalah urusan ingatan. Terdapat sejumlah besar cara untuk skru perkara, termasuk memperuntukkan jumlah memori yang salah, lupa untuk memulakan pembolehubah, bertulis sebelum atau selepas akhir penampan, dan membebaskan menyimpan pelbagai memori kali. Gejala terdiri daripada kemalangan sekejap kepada nilai misteri ditimpa, selalunya di tempat-tempat dan masa yang jauh dari kesilapan asal. Mengesan masalah diperhatikan kembali kepada punca asas boleh mencabar, tetapi mujurlah ada satu program yang membantu dipanggil Valgrind yang boleh melakukan banyak untuk membantu. Anda menjalankan program bawah Valgrind untuk membolehkan pemeriksaan luas peruntukan memori timbunan dan mengakses. Apabila Valgrind mengesan masalah, ia memberikan anda serta-merta, maklumat langsung yang membolehkan anda untuk lebih mudah mencari dan menyelesaikan masalah. Valgrind juga laporan mengenai isu-isu memori yang kurang maut, seperti kebocoran memori, memperuntukkan memori timbunan, dan lupa untuk membebaskan. Seperti pengkompil kami, dilafaz, penyahpepijat kami, GDB, Valgrind adalah perisian bebas, dan ia dipasang pada perkakas. Valgrind berjalan pada laku perduaan anda, tidak c anda atau h kod fail sumber, jadi pastikan anda telah kumpulkan salinan up-to-tarikh program anda menggunakan dilafaz atau Buat. Kemudian, menjalankan program anda di bawah Valgrind boleh semudah hanya awalan arahan program standard dengan Valgrind perkataan, yang bermula Valgrind dan menjalankan program di dalamnya. Apabila bermula, Valgrind melakukan beberapa kompleks jiggering untuk mengkonfigurasi executable untuk cek memori, supaya ia boleh mengambil sedikit untuk bangun dan berjalan. Program ini kemudiannya akan melaksanakan biasanya, ia lebih perlahan, dan apabila ia selesai, Valgrind akan mencetak ringkasan penggunaan memori. Jika semua berjalan lancar, ia akan kelihatan seperti ini: Dalam kes ini, / clean_program adalah laluan kepada program yang saya mahu untuk menjalankan. Dan manakala yang satu ini tidak mengambil apa-apa hujah, jika ia tidak saya mahu hanya jelujur mereka ke akhir arahan seperti biasa. Program bersih adalah hanya satu program bodoh sedikit saya mencipta yang memperuntukkan ruang untuk blok ints pada timbunan, meletakkan beberapa nilai di dalam mereka, dan membebaskan keseluruhan blok. Ini adalah apa yang anda menembak, tiada kesilapan dan tiada kebocoran. Satu lagi metrik penting ialah jumlah bait yang diperuntukkan. Bergantung kepada program, jika peruntukan anda berada dalam megabait atau lebih tinggi, anda mungkin melakukan sesuatu yang salah. Adakah anda tidak perlu menyimpan salinan? Adakah anda menggunakan timbunan untuk penyimpanan, apabila ia akan menjadi lebih baik untuk menggunakan timbunan? Jadi, kesilapan memori boleh menjadi benar-benar jahat. Orang-orang yang lebih terang-terangan menyebabkan kemalangan yang menakjubkan, tetapi walaupun begitu ia masih boleh menjadi sukar untuk menentukan apa sebenarnya membawa kepada kemalangan. Lebih insidiously, program dengan kesilapan memori masih boleh menyusun rapi dan masih boleh kelihatan untuk bekerja dengan betul kerana anda berjaya untuk mendapatkan bertuah kebanyakan masa. Selepas beberapa "hasil yang berjaya," anda mungkin berfikir bahawa kemalangan adalah kebetulan komputer, tetapi komputer tidak pernah salah. Running Valgrind boleh membantu anda mengesan punca kesilapan memori dilihat serta mencari mengintai kesilapan anda tidak lagi tahu tentang. Setiap kali Valgrind mengesan masalah, ia mencetak maklumat tentang apa yang ia diperhatikan. Setiap item adalah agak rapi - garis sumber arahan bersalah, apa isu, dan maklumat sedikit tentang memori yang terlibat - tetapi selalunya ia adalah maklumat yang cukup untuk mengarahkan perhatian anda ke tempat yang betul. Berikut adalah contoh Valgrind berjalan pada program kereta yang tidak membaca tidak sah memori timbunan. Kami melihat tidak ada kesilapan atau amaran dalam kompilasi. Uh-oh, ringkasan ralat mengatakan bahawa terdapat dua kesilapan - dua reads tidak sah daripada 4 saiz - bait, iaitu. Kedua-dua buruk berbunyi berlaku dalam fungsi utama invalid_read.c, pertama pada 16 baris dan kedua pada 19 baris. Mari kita lihat pada kod. Kelihatan seperti panggilan pertama untuk printf cuba untuk membaca satu int lalu akhir blok ingatan kita. Jika kita melihat kembali pada output Valgrind, kita lihat bahawa Valgrind memberitahu kita tepat. Alamat kita sedang cuba untuk membaca bermula 0 bytes lepas akhir blok saiz 16 bait - empat 32-bit ints bahawa kita memperuntukkan. Iaitu, alamat kita cuba membaca bermula tepat pada akhir blok kami, hanya seperti yang kita lihat dalam panggilan buruk printf kami. Sekarang, tidak sah dibaca mungkin tidak kelihatan seperti yang besar perjanjian, tetapi jika anda menggunakan data untuk mengawal aliran program anda - sebagai contoh, sebagai sebahagian daripada jika pernyataan atau gelung - kemudian perkara senyap boleh pergi buruk. Watch bagaimana saya boleh menjalankan program invalid_read dan apa-apa yang luar biasa berlaku. Menakutkan, kan? Sekarang, mari kita lihat di beberapa lagi jenis kesilapan yang mungkin anda temui di dalam kod anda, dan kita akan melihat bagaimana Valgrind mengesan mereka. Kami hanya melihat satu contoh invalid_read satu, jadi sekarang mari kita menyemak invalid_write. Sekali lagi, tiada kesilapan atau amaran dalam kompilasi. Okay, Valgrind mengatakan bahawa terdapat dua kesilapan dalam program ini - dan invalid_write dan invalid_read satu. Mari kita menyemak kod ini. Kelihatan seperti kita telah mendapat satu contoh daripada strlen klasik ditambah satu pepijat. Kod tidak malloc bait tambahan ruang untuk watak / 0, jadi apabila salinan str pergi untuk menulis di ssubstrlen "cs50 batu!" ia menulis 1 bait lepas akhir blok kami. Invalid_read datang apabila kita membuat panggilan kami untuk printf. Printf berakhir membaca memori tidak sah apabila ia membaca / 0 aksara kerana ia kelihatan pada akhir rentetan E ini ia percetakan. Tetapi tidak seorang pun daripada ini melarikan diri Valgrind. Kita lihat bahawa ia ditangkap invalid_write sebagai sebahagian daripada salinan str pada 11 barisan utama, dan invalid_read adalah sebahagian daripada printf. Rock, Valgrind. Sekali lagi, ini tidak mungkin kelihatan seperti perjanjian yang besar. Kita boleh menjalankan program ini berulang luar Valgrind dan tidak melihat sebarang tanda-tanda kesilapan. Walau bagaimanapun, mari kita melihat sedikit perbezaan ini untuk melihat bagaimana perkara boleh mendapatkan benar-benar buruk. Jadi, yang diberikan, kita menyalahgunakan perkara yang lebih daripada hanya sedikit dalam kod ini. Kami hanya memperuntukkan ruang pada timbunan selama dua rentetan panjang cs50 batu, masa ini, mengingat / 0 watak. Tetapi kemudian kita buang dalam rentetan super-panjang ke dalam blok memori S menunjuk ke. Apa kesan akan yang mempunyai blok memori yang menunjukkan T? Nah, jika mata T memori yang hanya bersebelahan S, datang hanya selepas ia, maka kita mungkin telah ditulis lebih sebahagian T. Mari kita menjalankan kod ini. Lihatlah apa yang berlaku. Rentetan kita disimpan dalam blok timbunan kami kedua-dua muncul telah dicetak dengan betul. Tiada apa-apa seolah-olah salah pada semua. Walau bagaimanapun, mari kita kembali ke dalam kod kami dan mengulas garis mana kita menyalin cs50 batu ke dalam blok memori yang kedua, menunjukkan oleh t. Sekarang, apabila kita menjalankan kod ini kita harus hanya melihat kandungan blok memori pertama mencetak keluar. Wah, walaupun kita tidak melakukan salinan str mana-mana aksara ke dalam blok timbunan kedua, satu menunjuk oleh T, kita dapat mencetak keluar. Malah, tali kita disumbat ke dalam blok pertama kita Mekah blok pertama dan ke blok kedua, membuat segala-galanya kelihatan normal. Valgrind, walaupun, memberitahu kita cerita benar. Terdapat kita pergi. Semua orang-orang yang tidak sah membaca dan menulis. Mari kita lihat pada contoh jenis lain kesilapan. Di sini kita melakukan sesuatu yang agak malang. Kami merebut ruang untuk int pada timbunan, dan kami memulakan penunjuk int - p - untuk menunjukkan ruang yang. Walau bagaimanapun, manakala penunjuk kami dimulakan, data yang ia menunjuk kepada hanya apa jua ringan adalah di bahagian timbunan. Jadi apabila kita memuatkan bahawa data ke dalam int i, kita teknikal memulakan i, tetapi kita berbuat demikian dengan data sampah. Panggilan untuk menegaskan, yang merupakan makro debugging berguna ditakrifkan dalam perpustakaan yang dinamakan menegaskan, akan membatalkan program jika keadaan ujian gagal. Iaitu, jika saya tidak adalah 0. Bergantung pada apa yang berada di ruang timbunan itu, menunjukkan oleh p, program ini mungkin bekerja dan kadang-kadang gagal pada masa yang lain. Jika ia berfungsi, kita hanya mendapat bertuah. Pengkompil tidak akan menangkap kesilapan ini, tetapi Valgrind kehendak pasti. Ada kita lihat kesilapan yang berpunca daripada penggunaan kami bahawa data sampah. Apabila anda memperuntukkan memori timbunan tetapi tidak deallocate atau membebaskannya, yang dipanggil kebocoran. Untuk kecil, program singkat yang berjalan dan segera keluar, kebocoran yang agak tidak berbahaya, tetapi untuk projek saiz yang lebih besar dan / atau panjang umur, walaupun kebocoran kecil boleh mengkompaun menjadi sesuatu yang utama. Bagi CS50, kami mengharapkan anda untuk menjaga membebaskan semua memori timbunan bahawa anda memperuntukkan, kerana kami ingin anda untuk membina kemahiran untuk betul mengendalikan proses manual dikehendaki oleh C. Untuk berbuat demikian, program anda harus mempunyai yang tepat satu-satu surat-menyurat antara malloc dan panggilan percuma. Mujurlah, Valgrind boleh membantu anda dengan kebocoran memori juga. Berikut adalah program bocor dipanggil leak.c yang memperuntukkan ruang pada timbunan, menulis kepadanya, tetapi tidak membebaskan. Kami menyusun dengan Membuat dan menjalankan di bawah Valgrind, dan kita lihat bahawa, sementara kita tidak mempunyai ralat memori, kita mempunyai satu kebocoran. Terdapat 16 bytes pasti hilang, bermakna bahawa penunjuk kepada memori yang tidak berada dalam skop apabila program keluar. Sekarang, Valgrind tidak memberikan kita satu tan maklumat tentang kebocoran, tetapi jika kita mengikuti nota ini sedikit bahawa ia memberikan ke arah bahagian bawah laporan untuk memutarkan lagi dengan kebocoran menyemak = penuh untuk melihat butiran penuh memori bocor, kita akan mendapatkan maklumat lanjut. Sekarang, dalam ringkasan timbunan, Valgrind memberitahu kita di mana memori yang hilang pada mulanya diperuntukkan. Sama seperti kita tahu dari melihat dalam kod sumber, Valgrind memberitahu kita bahawa kita bocor memori yang diperuntukkan dengan panggilan malloc on line 8 daripada leak.c dalam fungsi utama. Cukup bagus. Valgrind mengkategorikan kebocoran menggunakan istilah-istilah ini: Pasti hilang - ini adalah memori timbunan diperuntukkan yang program ini tidak lagi mempunyai penunjuk. Valgrind tahu bahawa anda pernah penunjuk tetapi telah sejak hilang mengesan ia. Memori ini pasti bocor. Secara tidak langsung hilang - ini adalah memori timbunan diperuntukkan yang petunjuk sahaja ia juga hilang. Sebagai contoh, jika anda kehilangan penunjuk anda untuk nod pertama senarai berkaitan, maka nod pertama itu sendiri akan pasti hilang, semasa mana-mana nod berikutnya akan secara tidak langsung hilang. Mungkin hilang - ini adalah memori timbunan diperuntukkan yang Valgrind tidak boleh pasti sama ada terdapat penunjuk atau tidak. Masih dicapai memori timbunan diperuntukkan yang program ini masih mempunyai penunjuk di bahagian keluar, yang biasanya bermaksud bahawa mata global yang berubah-ubah untuk ia. Untuk memeriksa kebocoran ini, anda juga akan mempunyai termasuk pilihan - Masih dikunjungi = ya dalam doa anda Valgrind. Kes-kes yang berbeza mungkin memerlukan strategi yang berbeza untuk membersihkan mereka, tetapi kebocoran hendaklah dihapuskan. Malangnya, menetapkan kebocoran boleh menjadi sukar untuk dilakukan, sejak panggilan tidak betul untuk bebas boleh meletupkan program anda. Sebagai contoh, jika kita melihat di invalid_free.c, kita lihat satu contoh deallocation memori buruk. Apa yang perlu panggilan tunggal untuk membebaskan seluruh blok memori menunjukkan oleh int_block, sebaliknya telah menjadi satu cubaan untuk membebaskan setiap seksyen int bersaiz memori individu. Ini akan gagal catastrophically. Boom! Apa ralat. Ini memang tidak baik. Jika anda terjebak dengan jenis ini kesilapan, walaupun, dan anda tidak tahu di mana untuk melihat, jatuh kembali pada rakan baru anda yang terbaik. Anda fikirkan - Valgrind. Valgrind, seperti biasa, tahu apa terpulang. Tuduhan alloc dan bebas tidak sepadan. Kami telah mendapat 1 alloc dan 4 membebaskan. Dan Valgrind juga memberitahu kita di mana panggilan pertama percuma buruk - satu yang mencetuskan blowup - datang dari - line 16. Seperti yang anda lihat, panggilan buruk untuk membebaskan adalah benar-benar buruk, jadi kami cadangkan membiarkan kebocoran program anda semasa anda sedang berusaha untuk mendapatkan fungsi betul. Mula mencari kebocoran hanya selepas program anda berfungsi dengan betul, tanpa apa-apa kesilapan lain. Dan itu semua kita telah mendapat untuk video ini. Sekarang apa yang anda tunggu? Pergi berjalan Valgrind pada program anda sekarang. Nama saya adalah Nate Hardison. Ini adalah CS50. [CS50.TV]