[Powered by Google Translate] [Valgrind]
[Nate Hardison, Universitas Harvard]
Ini adalah CS50, CS50.TV]
Beberapa bug yang paling sulit dalam program C
berasal dari salah urus memori.
Ada sejumlah besar cara untuk mengacaukan segalanya,
termasuk mengalokasikan jumlah yang salah dari memori,
lupa untuk menginisialisasi variabel,
menulis sebelum atau setelah akhir dari buffer,
dan membebaskan menjaga kali memori beberapa.
Gejala berkisar dari crash intermiten
nilai-nilai misterius ditimpa,
sering pada tempat dan waktu jauh dari kesalahan aslinya.
Menelusuri masalah diamati kembali ke akar penyebab yang mendasari
dapat menantang,
tapi untungnya ada program membantu disebut Valgrind
yang dapat melakukan banyak hal untuk membantu.
>> Anda menjalankan program di bawah Valgrind untuk mengaktifkan
ekstensif memeriksa alokasi memori tumpukan dan akses.
Ketika Valgrind mendeteksi masalah, itu memberikan Anda langsung,
Informasi langsung yang memungkinkan Anda untuk
lebih mudah menemukan dan memperbaiki masalah.
Valgrind juga laporan tentang masalah memori kurang mematikan,
seperti kebocoran memori, mengalokasikan memori heap,
dan lupa untuk membebaskan itu.
Seperti compiler kami, dentang, dalam debugger kami, GDB,
Valgrind adalah perangkat lunak bebas, dan dipasang pada alat.
Valgrind berjalan pada executable biner Anda,
Anda tidak c atau. file sumber. kode h,
jadi pastikan Anda telah mengumpulkan salinan up-to-date dari program Anda
menggunakan dentang atau Membuat.
Kemudian, menjalankan program Anda di bawah Valgrind dapat
sesederhana hanya awalan perintah program standar dengan Valgrind kata,
yang dijalankan Valgrind dan menjalankan program di dalamnya.
Ketika mulai, Valgrind melakukan beberapa kompleks
Sulap untuk mengkonfigurasi eksekusi untuk pemeriksaan memori,
sehingga dapat mengambil sedikit untuk bangun dan berjalan.
Program ini kemudian akan menjalankan normal, akan jauh lebih lambat,
dan ketika selesai, Valgrind akan mencetak ringkasan penggunaan memori.
Jika semua berjalan dengan baik, maka akan terlihat seperti ini:
Dalam kasus ini, / clean_program.
adalah path dari program yang saya ingin menjalankan.
Dan sementara yang satu ini tidak mengambil argumen,
jika hal itu aku baru saja taktik mereka ke akhir perintah seperti biasa.
Program bersih hanyalah sebuah program kecil yang konyol saya buat
yang mengalokasikan ruang untuk blok ints di heap,
menempatkan beberapa nilai dalam diri mereka, dan membebaskan seluruh blok.
Ini adalah apa yang Anda sedang syuting untuk, tidak ada kesalahan dan tidak ada kebocoran.
>> Metrik lain yang penting adalah jumlah byte dialokasikan.
Tergantung pada program tersebut, jika alokasi Anda berada di megabyte atau lebih tinggi,
Anda mungkin melakukan sesuatu yang salah.
Apakah Anda tidak perlu menyimpan duplikat?
Apakah Anda menggunakan tumpukan untuk penyimpanan, ketika itu akan lebih baik untuk menggunakan stack?
Jadi, kesalahan memori dapat benar-benar jahat.
Yang lebih jelas menyebabkan crash spektakuler,
tetapi itu pun masih akan sulit untuk menentukan
apa sebenarnya menyebabkan kecelakaan.
Lebih diam-diam, sebuah program dengan kesalahan memori
masih bisa mengkompilasi bersih
dan masih bisa bekerja dengan benar
karena Anda berhasil mendapatkan beruntung sebagian besar waktu.
Setelah beberapa "hasil yang sukses,"
Anda mungkin hanya berpikir bahwa kecelakaan adalah kebetulan dari komputer,
tapi komputer tidak pernah salah.
>> Menjalankan Valgrind dapat membantu Anda melacak penyebab kesalahan memori terlihat
serta menemukan mengintai kesalahan Anda bahkan tidak tahu tentang belum.
Setiap kali Valgrind mendeteksi masalah, mencetak informasi tentang apa yang diamati.
Setiap item cukup singkat -
garis sumber instruksi menyinggung, apa masalah ini,
dan sedikit info tentang memori yang terlibat -
tetapi sering itu informasi yang cukup untuk mengarahkan perhatian Anda ke tempat yang tepat.
Berikut adalah contoh dari Valgrind berjalan pada program kereta
yang melakukan bacaan yang valid dari memori tumpukan.
Kami melihat tidak ada kesalahan atau peringatan dalam kompilasi.
Uh-oh, ringkasan kesalahan mengatakan bahwa ada dua kesalahan -
dua valid dibaca ukuran 4 - byte, yaitu.
Kedua buruk membaca terjadi dalam fungsi utama invalid_read.c,
yang pertama pada baris 16 dan kedua pada baris 19.
Mari kita lihat kode.
Sepertinya panggilan pertama untuk printf mencoba untuk membaca satu int melewati ujung blok memori kita.
Jika kita melihat kembali pada output Valgrind itu,
kita melihat bahwa Valgrind memberitahu kami persis seperti itu.
Alamat kami mencoba untuk membaca mulai 0 byte
melewati ujung blok ukuran 16 byte -
empat 32-bit ints yang kita dialokasikan.
Artinya, alamat kami mencoba membaca dimulai tepat di ujung blok kami,
seperti kita lihat dalam panggilan yang buruk printf kami.
Sekarang, tidak valid dibaca mungkin tidak terlihat seperti itu masalah besar,
tetapi jika Anda menggunakan data tersebut untuk mengontrol aliran program anda -
Misalnya, sebagai bagian dari jika pernyataan atau loop -
maka hal-hal diam-diam bisa pergi buruk.
Perhatikan bagaimana saya bisa menjalankan program invalid_read
dan tidak ada yang luar biasa terjadi.
Menakutkan, ya?
>> Sekarang, mari kita lihat jenis lagi kesalahan yang mungkin Anda alami dalam kode Anda,
dan kita akan melihat bagaimana Valgrind mendeteksi mereka.
Kami hanya melihat contoh sebuah invalid_read,
jadi sekarang mari kita periksa invalid_write suatu.
Sekali lagi, tidak ada kesalahan atau peringatan dalam kompilasi.
Oke, Valgrind mengatakan bahwa ada dua kesalahan dalam program ini -
dan invalid_write dan invalid_read sebuah.
Mari kita periksa kode ini.
Sepertinya kita punya sebuah instance dari strlen klasik ditambah satu bug.
Kode tidak malloc byte ekstra ruang
untuk karakter / 0,
jadi ketika copy str pergi untuk menulis itu di ssubstrlen "cs50 rocks!"
itu aja 1 byte melewati ujung blok kami.
Invalid_read datang ketika kita melakukan panggilan kita untuk printf.
Printf berakhir membaca memori yang tidak valid ketika membaca / 0 karakter
seperti yang terlihat pada akhir string E itu pencetakan.
Tapi semua ini lolos Valgrind.
Kami melihat bahwa itu tertangkap invalid_write sebagai bagian dari salinan str
on line 11 main, dan invalid_read adalah bagian dari printf.
Batu pada, Valgrind.
Sekali lagi, ini mungkin tidak tampak seperti masalah besar.
Kita dapat menjalankan program ini berulang luar Valgrind
dan tidak melihat gejala kesalahan.
>> Namun, mari kita lihat sedikit variasi dari ini untuk melihat
bagaimana hal-hal bisa benar-benar buruk.
Jadi, diberikan, kita menyalahgunakan hal-hal lebih dari hanya sedikit dalam kode ini.
Kami hanya mengalokasikan ruang di heap untuk dua string
panjang cs50 batu,
saat ini, mengingat / 0 karakter.
Tapi kemudian kami melempar string super-panjang ke dalam blok memori
S yang menunjuk ke.
Apa efek yang akan yang memiliki di blok memori yang menunjuk T untuk?
Nah, jika poin T untuk memori yang hanya berbatasan dengan S,
datang hanya setelah itu,
maka kita mungkin telah ditulis di atas bagian dari T.
Mari kita menjalankan kode ini.
Lihatlah apa yang terjadi.
Senar kita disimpan dalam blok tumpukan kami baik tampaknya telah dicetak dengan benar.
Sepertinya tidak ada yang salah sama sekali.
Namun, mari kita kembali ke dalam kode dan
komentar dari baris di mana kita copy cs50 batu
ke blok memori kedua, ditunjuk oleh t.
Sekarang, ketika kita menjalankan kode ini kita harus
hanya melihat isi dari blok memori pertama mencetak.
Whoa, meskipun kita tidak copy str
setiap karakter ke dalam blok tumpukan kedua, yang ditunjuk oleh T,
kita mendapatkan print out.
Memang, string kita dimasukkan ke blok pertama kami
menyerbu blok pertama dan ke blok kedua,
membuat segalanya tampak normal.
Valgrind, meskipun, menceritakan kisah nyata.
Di sana kami pergi.
Semua itu tidak valid membaca dan menulis.
>> Mari kita lihat contoh lain jenis kesalahan.
Di sini kita melakukan sesuatu yang agak disayangkan.
Kami ambil ruang untuk int di heap,
dan kita menginisialisasi sebuah pointer int - p - untuk menunjuk ke ruang tersebut.
Namun, sementara kami pointer diinisialisasi,
data bahwa itu menunjuk hanya telah apapun sampah adalah di bagian tumpukan.
Jadi ketika kita memuat data ke int i,
kita secara teknis menginisialisasi i,
tapi kami melakukannya dengan data sampah.
Panggilan untuk menegaskan, yang merupakan makro debugging berguna
didefinisikan dalam perpustakaan menegaskan aptly bernama,
akan membatalkan program jika kondisi pengujian yang gagal.
Artinya, jika saya tidak 0.
Tergantung pada apa yang ada di ruang tumpukan, ditunjuk oleh p,
Program ini bisa bekerja kadang-kadang dan gagal di lain waktu.
Jika berhasil, kita hanya mendapatkan beruntung.
Compiler tidak akan menangkap kesalahan ini, tapi Valgrind kehendak yakin.
Di sana kita melihat kesalahan yang berasal dari penggunaan kami data sampah.
>> Bila Anda mengalokasikan memori heap tetapi tidak DEALLOCATE atau membebaskannya,
yang disebut kebocoran.
Untuk program, kecil berumur pendek yang berjalan dan segera keluar,
kebocoran cukup berbahaya,
tapi untuk proyek ukuran yang lebih besar dan / atau umur panjang,
bahkan kebocoran kecil dapat senyawa menjadi sesuatu yang besar.
Untuk CS50, kami mengharapkan Anda untuk
mengurus membebaskan semua memori tumpukan yang Anda mengalokasikan,
karena kami ingin Anda untuk membangun keterampilan untuk benar menangani proses manual
dibutuhkan oleh C.
Untuk melakukannya, program Anda harus memiliki tepat
satu-ke-satu korespondensi antara malloc dan panggilan gratis.
Untungnya, Valgrind dapat membantu Anda dengan kebocoran memori juga.
Berikut ini adalah sebuah program yang disebut bocor leak.c yang mengalokasikan
ruang di heap, menulis untuk itu, tetapi tidak membebaskannya.
Kami compile dengan Membuat dan menjalankannya di bawah Valgrind,
dan kita melihat bahwa, sementara kita tidak memiliki kesalahan memori,
kita memiliki satu kebocoran.
Ada 16 byte pasti hilang,
yang berarti bahwa pointer ke memori yang tidak dalam lingkup saat program keluar.
Sekarang, Valgrind tidak memberi kita satu ton informasi tentang kebocoran,
tetapi jika kita mengikuti catatan kecil yang memberikan turun ke bagian bawah laporannya
untuk mengulangi dengan - kebocoran-cek penuh =
untuk melihat rincian lengkap dari memori bocor,
kita akan mendapatkan informasi lebih lanjut.
Sekarang, dalam ringkasan tumpukan,
Valgrind memberitahu kita di mana memori yang hilang awalnya dialokasikan.
Sama seperti yang kita tahu dari melihat dalam kode sumber,
Valgrind memberitahu kita bahwa kita bocor memori
dialokasikan dengan panggilan untuk malloc on line 8 dari leak.c
dalam fungsi utama.
Cukup bagus.
>> Valgrind mengkategorikan kebocoran menggunakan istilah-istilah ini:
Pasti hilang - ini adalah memori yang dialokasikan heap
yang program tidak lagi memiliki pointer.
Valgrind tahu bahwa Anda pernah memiliki pointer tetapi sejak kehilangan jejak itu.
Memori ini pasti bocor.
Secara tidak langsung hilang - ini adalah memori yang dialokasikan heap
dimana pointer hanya untuk itu juga hilang.
Misalnya, jika Anda kehilangan pointer Anda ke simpul pertama dari linked list,
maka node pertama itu sendiri akan benar-benar hilang,
sementara setiap node berikutnya akan langsung hilang.
Mungkin hilang - ini adalah memori yang dialokasikan heap
yang Valgrind tidak dapat memastikan apakah ada pointer atau tidak.
Masih terjangkau adalah memori yang dialokasikan heap
yang program ini masih memiliki pointer di pintu keluar,
yang biasanya berarti bahwa poin variabel global untuk itu.
Untuk memeriksa kebocoran tersebut, Anda juga harus menyertakan opsi
- Masih terjangkau = yes
dalam doa Anda Valgrind.
>> Kasus-kasus yang berbeda mungkin memerlukan strategi yang berbeda untuk membersihkan mereka,
namun kebocoran harus dihilangkan.
Sayangnya, memperbaiki kebocoran bisa sulit untuk dilakukan,
karena panggilan tidak benar untuk membebaskan dapat meledakkan program Anda.
Sebagai contoh, jika kita melihat invalid_free.c,
kita melihat contoh dealokasi memori buruk.
Apa yang harus menjadi satu panggilan untuk membebaskan seluruh blok
dari memori yang ditunjuk oleh int_block,
malah menjadi upaya untuk membebaskan setiap bagian int berukuran
dari memori individual.
Ini akan gagal serempak.
Boom! Apa kesalahan.
Ini jelas tidak baik.
Jika Anda terjebak dengan jenis kesalahan ini, meskipun, dan Anda tidak tahu di mana mencarinya,
jatuh kembali pada teman baru terbaik Anda.
Anda dapat menebaknya - Valgrind.
Valgrind, seperti biasa, tahu persis apa yang terjadi.
Penghitungan alokasi dan bebas tidak cocok.
Kami punya 1 alloc dan 4 membebaskan.
Dan Valgrind juga memberitahu kita di mana panggilan bebas pertama yang buruk -
salah satu yang memicu blowup - adalah berasal dari -
baris 16.
Seperti yang Anda lihat, panggilan buruk untuk membebaskan benar-benar buruk,
jadi kami sarankan membiarkan kebocoran program Anda
saat Anda sedang bekerja untuk mendapatkan fungsi yang benar.
Mulai mencari kebocoran hanya setelah program Anda bekerja dengan benar,
tanpa kesalahan lainnya.
>> Dan itu yang kita punya untuk video ini.
Sekarang apa yang Anda tunggu?
Pergi menjalankan Valgrind pada program Anda sekarang.
Nama saya adalah Nate Hardison. Ini adalah CS50. [CS50.TV]