Seberapa berbahaya mengakses array di luar batas?

221

Seberapa berbahaya mengakses array di luar batasnya (dalam C)? Kadang-kadang dapat terjadi bahwa saya membaca dari luar array (saya sekarang mengerti saya kemudian mengakses memori yang digunakan oleh beberapa bagian lain dari program saya atau bahkan lebih dari itu) atau saya mencoba untuk menetapkan nilai ke indeks di luar array. Program terkadang macet, tetapi terkadang hanya berjalan, hanya memberikan hasil yang tidak terduga.

Sekarang yang ingin saya ketahui adalah, seberapa berbahayakah ini sebenarnya? Jika itu merusak program saya, itu tidak terlalu buruk. Jika di sisi lain itu merusak sesuatu di luar program saya, karena saya entah bagaimana berhasil mengakses beberapa memori yang sama sekali tidak terkait, maka itu sangat buruk, saya kira. Saya membaca banyak 'apa pun bisa terjadi', 'segmentasi mungkin menjadi masalah paling tidak buruk' , 'hard disk Anda mungkin menjadi merah muda dan unicorn mungkin bernyanyi di bawah jendela Anda', yang semuanya bagus, tapi apa sebenarnya bahayanya?

Pertanyaan saya:

  1. Bisakah membaca nilai dari jauh di luar array merusak apa pun selain program saya? Saya akan membayangkan hanya melihat hal-hal tidak mengubah apa pun, atau apakah itu misalnya mengubah atribut 'terakhir kali dibuka' dari file yang kebetulan saya jangkau?
  2. Dapatkah menetapkan nilai-nilai di luar array merusak sesuatu selain dari program saya? Dari pertanyaan Stack Overflow ini saya menyimpulkan bahwa dimungkinkan untuk mengakses lokasi memori mana pun, bahwa tidak ada jaminan keamanan.
  3. Saya sekarang menjalankan program kecil saya dari dalam XCode. Apakah itu memberikan perlindungan ekstra di sekitar program saya di mana ia tidak dapat menjangkau di luar ingatannya sendiri? Bisakah itu membahayakan XCode?
  4. Adakah rekomendasi tentang cara menjalankan kode bawaan kereta saya dengan aman?

Saya menggunakan OSX 10.7, Xcode 4.6.

ChrisD
sumber
Secara umum, OS akan melindungi dirinya sendiri dan proses lainnya dari penyimpangan Anda. Namun, itu bukan sesuatu yang ingin Anda andalkan.
Hot Licks
7
Juga, Anda tidak akan pernah "mencapai" file pada hard disk Anda ketika mengakses dan menyusun indeks di luar batas (dalam ram Anda).
DrummerB
1
Saya percaya Anda bertanya tentang array C, kan? jadi itu tidak ada hubungannya dengan ObjC dan tidak benar-benar berhubungan dengan IDE.
Bryan Chen
17
Inilah contoh favorit saya tentang hasil aneh (ini berkaitan dengan tumpukan, tapi saya merasa ini sangat mencerahkan ...).
phipsgabler
11
xkcd.com/371
Dan Is Fiddling Oleh Firelight

Jawaban:

125

Sejauh standar ISO C (definisi resmi bahasa) yang bersangkutan, mengakses array di luar batasnya memiliki " perilaku tidak terdefinisi ". Arti harfiah dari ini adalah:

perilaku, setelah menggunakan konstruksi program yang tidak dapat diakses atau salah atau data yang salah, yang untuknya Standar Internasional ini tidak mengharuskan persyaratan

Catatan non-normatif memperluas ini:

Kemungkinan perilaku yang tidak terdefinisi mulai dari mengabaikan situasi sepenuhnya dengan hasil yang tidak terduga, hingga berperilaku selama penerjemahan atau pelaksanaan program dengan cara yang terdokumentasi, karakteristik lingkungan (dengan atau tanpa penerbitan pesan diagnostik), hingga penghentian terjemahan atau eksekusi (dengan penerbitan pesan diagnostik).

Jadi itu teorinya. Apa kenyataannya?

Dalam kasus "terbaik", Anda akan mengakses sebagian memori yang dimiliki oleh program yang sedang berjalan (yang mungkin menyebabkan program Anda salah tingkah), atau yang tidak dimiliki oleh program yang sedang berjalan (yang mungkin akan menyebabkan program Anda crash dengan sesuatu seperti kesalahan segmentasi). Atau Anda mungkin mencoba menulis ke memori yang dimiliki program Anda, tetapi itu ditandai hanya baca; ini mungkin juga akan menyebabkan program Anda macet.

Itu dengan asumsi program Anda berjalan di bawah sistem operasi yang mencoba untuk melindungi proses yang berjalan bersamaan dari satu sama lain. Jika kode Anda berjalan pada "bare metal", katakanlah jika itu bagian dari kernel OS atau sistem tertanam, maka tidak ada perlindungan seperti itu; kode perilaku buruk Anda adalah apa yang seharusnya memberikan perlindungan itu. Dalam hal itu, kemungkinan kerusakan jauh lebih besar, termasuk, dalam beberapa kasus, kerusakan fisik pada perangkat keras (atau benda-benda atau orang-orang di sekitarnya).

Bahkan dalam lingkungan OS yang dilindungi, perlindungan tidak selalu 100%. Ada bug sistem operasi yang mengizinkan program yang tidak terjangkau untuk mendapatkan akses root (administratif), misalnya. Bahkan dengan hak pengguna biasa, program yang tidak berfungsi dapat menggunakan sumber daya yang berlebihan (CPU, memori, disk), mungkin menjatuhkan seluruh sistem. Banyak malware (virus, dll.) Mengeksploitasi buffer overruns untuk mendapatkan akses tidak sah ke sistem.

(Satu contoh historis: Saya pernah mendengar bahwa pada beberapa sistem lama dengan memori inti , berulang kali mengakses satu lokasi memori dalam satu lingkaran ketat dapat benar-benar menyebabkan potongan memori meleleh. Kemungkinan lain termasuk menghancurkan layar CRT, dan memindahkan bacaan. / tulis kepala drive disk dengan frekuensi harmonik kabinet drive, yang menyebabkannya melintasi meja dan jatuh ke lantai.)

Dan selalu ada Skynet yang perlu dikhawatirkan.

Intinya adalah ini: jika Anda dapat menulis sebuah program untuk melakukan sesuatu yang buruk dengan sengaja , setidaknya secara teoritis mungkin bahwa program kereta bisa melakukan hal yang sama secara tidak sengaja .

Dalam praktiknya, sangat tidak mungkin program kereta Anda berjalan pada sistem MacOS X akan melakukan sesuatu yang lebih serius daripada crash. Tapi itu tidak mungkin untuk sepenuhnya mencegah kode buggy dari melakukan hal-hal yang sangat buruk.

Keith Thompson
sumber
1
terima kasih, saya sebenarnya mengerti sepenuhnya hal ini. Tapi itu segera memicu pertanyaan lanjutan: apa yang bisa dilakukan oleh seorang programmer pemula, untuk melindungi komputernya dari kreasi yang mungkin mengerikan? Setelah saya menguji suatu program secara menyeluruh, saya dapat melepaskannya di dunia. Tetapi uji coba pertama pasti akan menjadi program yang salah. Bagaimana kalian menjaga sistem Anda aman dari diri Anda sendiri?
ChrisD
6
@ Chris: Kita cenderung beruntung. 8-)} Serius, perlindungan tingkat OS cukup bagus akhir-akhir ini. Kasus terburuk, jika saya menulis bom fork kebetulan , saya mungkin harus reboot untuk memulihkan. Tetapi kerusakan nyata pada sistem mungkin tidak perlu dikhawatirkan, selama program Anda tidak mencoba melakukan sesuatu yang berbahaya. Jika Anda benar-benar khawatir, menjalankan program pada mesin virtual mungkin bukan ide yang buruk.
Keith Thompson
1
Di sisi lain, saya telah melihat banyak hal aneh terjadi pada komputer yang saya gunakan (file rusak, kesalahan sistem yang tidak dapat dipulihkan, dll.), Dan saya tidak tahu berapa banyak di antaranya yang mungkin disebabkan oleh beberapa program C yang menunjukkan perilaku yang tidak terdefinisi yang ditakuti. (Sejauh ini tidak ada iblis yang sebenarnya terbang keluar dari hidung saya.)
Keith Thompson
1
terima kasih telah mengajari saya bom fork - saya telah melakukan hal-hal yang dekat dengan itu, ketika mencoba untuk memahami rekursi :)
ChrisD
2
scientificamerican.com/article/… sehingga api masih mungkin terjadi dengan elektronik modern.
Mooing Duck
25

Secara umum, Sistem Operasi saat ini (yang paling populer) menjalankan semua aplikasi di wilayah memori yang dilindungi menggunakan manajer memori virtual. Ternyata tidak MUDAH (per katakan) cukup membaca atau menulis ke lokasi yang ada di ruang NYATA di luar wilayah yang telah ditugaskan / dialokasikan untuk proses Anda.

Jawaban langsung:

1) Membaca hampir tidak akan pernah secara langsung merusak proses lain, namun secara tidak langsung dapat merusak proses jika Anda membaca nilai KUNCI yang digunakan untuk mengenkripsi, mendekripsi, atau memvalidasi program / proses. Pembacaan di luar batas dapat berdampak buruk / tidak terduga pada kode Anda jika Anda membuat keputusan berdasarkan data yang Anda baca

2) Satu-satunya cara Anda dapat benar-benar KERUSAKAN sesuatu dengan menulis ke tempat yang dapat diakses oleh alamat memori adalah jika alamat memori yang Anda tulis sebenarnya adalah register perangkat keras (lokasi yang sebenarnya bukan untuk penyimpanan data tetapi untuk mengendalikan beberapa bagian perangkat keras) bukan lokasi RAM. Pada kenyataannya, Anda biasanya tidak akan merusak sesuatu kecuali Anda menulis suatu lokasi terprogram yang tidak dapat ditulis ulang (atau sesuatu yang sifatnya seperti itu).

3) Secara umum berjalan dari dalam debugger menjalankan kode dalam mode debug. Berjalan dalam mode debug cenderung untuk (tetapi tidak selalu) menghentikan kode Anda lebih cepat ketika Anda telah melakukan sesuatu yang dianggap tidak praktis atau benar-benar ilegal.

4) Jangan pernah menggunakan makro, gunakan struktur data yang sudah memiliki batas indeks array memeriksa built in, dll ....

TAMBAHAN Saya harus menambahkan bahwa informasi di atas hanya untuk sistem yang menggunakan sistem operasi dengan jendela perlindungan memori. Jika menulis kode untuk sistem tertanam atau bahkan sistem yang memanfaatkan sistem operasi (real-time atau lainnya) yang tidak memiliki jendela perlindungan memori (atau jendela yang ditangani secara virtual), orang harus lebih berhati-hati dalam membaca dan menulis ke memori. Juga dalam kasus ini praktik pengkodean AMAN dan AMAN harus selalu digunakan untuk menghindari masalah keamanan.

terompet
sumber
4
Praktik pengkodean yang aman dan aman harus selalu digunakan.
Nik Bougalis
3
Saya sarankan TIDAK menggunakan try / catch untuk kode buggy kecuali Anda menangkap pengecualian yang sangat spesifik dan tahu bagaimana memulihkannya. Catch (...) adalah hal terburuk yang dapat Anda tambahkan ke kode kereta.
Eugene
1
@NikBougalis - Saya sepenuhnya setuju, tetapi BAHKAN LEBIH PENTING jika OS tidak menyertakan perlindungan memori / ruang alamat virtual, atau ada kekurangan OS :-)
trumpetlicks
@Eugene - Saya tidak pernah melihat itu menjadi masalah bagi saya, tapi saya setuju dengan Anda, apakah saya sudah mengeditnya :-)
trumpetlicks
1) maksudmu kerusakan karena aku akan mengungkapkan sesuatu yang seharusnya tetap dirahasiakan? 2) Saya tidak yakin mendapatkan maksud Anda, tetapi saya kira saya hanya mengakses RAM dengan mencoba mengakses lokasi di luar batas array?
ChrisD
9

Tidak memeriksa batas dapat menyebabkan efek samping yang buruk, termasuk lubang keamanan. Salah satu yang jelek adalah eksekusi kode arbitrer . Dalam contoh klasik: jika Anda memiliki array ukuran tetap, dan gunakan strcpy()untuk meletakkan string yang disediakan pengguna di sana, pengguna dapat memberi Anda string yang meluap buffer dan menimpa lokasi memori lainnya, termasuk alamat kode tempat CPU harus kembali ketika fungsi Anda selesai.

Yang berarti pengguna Anda dapat mengirim Anda string yang akan membuat program Anda pada dasarnya menelepon exec("/bin/sh"), yang akan mengubahnya menjadi shell, mengeksekusi apa pun yang dia inginkan di sistem Anda, termasuk memanen semua data Anda dan mengubah mesin Anda menjadi botnet node.

Lihat Menghancurkan Stack Untuk Kesenangan dan Keuntungan untuk detail tentang bagaimana hal ini dapat dilakukan.

che
sumber
Saya tahu bahwa saya tidak boleh mengakses elemen array di luar batas, terima kasih telah memperkuat titik itu. Tetapi pertanyaannya adalah, selain melakukan segala macam kerusakan pada program saya, dapatkah saya secara tidak sengaja menjangkau melampaui memori program saya? Dan maksud saya di OSX.
ChrisD
@ ChrisD: OS X adalah sistem operasi modern, sehingga akan memberi Anda perlindungan memori penuh. Misalnya Anda tidak boleh terbatas pada apa yang diperbolehkan untuk dilakukan oleh program Anda. Ini seharusnya tidak termasuk mengacaukan proses lain (kecuali jika Anda menjalankan hak root).
che
Saya lebih suka mengatakan di bawah ring 0 hak istimewa, bukan yang root.
Ruslan
Lebih menarik adalah bahwa kompiler hiper-modern mungkin memutuskan bahwa jika mencoba kode untuk membaca foo[0]melalui foo[len-1]setelah sebelumnya digunakan cek lenterhadap panjang array baik mengeksekusi atau melewatkan sepotong kode, compiler harus merasa bebas untuk menjalankan kode lainnya tanpa syarat bahkan jika aplikasi memiliki penyimpanan melewati array dan efek dari membacanya akan jinak, tetapi efek dari memohon kode lain tidak akan.
supercat
8

Anda menulis:

Saya membaca banyak 'apa pun bisa terjadi', 'segmentasi mungkin menjadi masalah paling tidak buruk', 'harddisk Anda mungkin menjadi merah muda dan unicorn mungkin bernyanyi di bawah jendela Anda', yang semuanya bagus, tapi apa sebenarnya bahayanya?

Mari kita begini: memuat pistol. Arahkan di luar jendela tanpa tujuan dan api tertentu. Apa bahayanya?

Masalahnya adalah Anda tidak tahu. Jika kode Anda menimpa sesuatu yang membuat crash program Anda, Anda akan baik-baik saja karena akan menghentikannya ke status yang ditentukan. Namun jika tidak macet maka masalah mulai muncul. Sumber daya apa yang berada di bawah kendali program Anda dan apa pengaruhnya terhadap mereka? Sumber daya apa yang mungkin berada di bawah kendali program Anda dan apa pengaruhnya terhadap mereka? Saya tahu setidaknya satu masalah besar yang disebabkan oleh luapan seperti itu. Masalahnya adalah dalam fungsi statistik yang tampaknya tidak berarti yang mengacaukan beberapa tabel konversi yang tidak terkait untuk database produksi. Hasilnya adalah beberapa pembersihan yang sangat mahal sesudahnya. Sebenarnya itu akan jauh lebih murah dan lebih mudah untuk ditangani jika masalah ini akan memformat hard disk ... dengan kata lain: unicorn merah muda mungkin menjadi masalah Anda.

Gagasan bahwa sistem operasi Anda akan melindungi Anda optimis. Jika mungkin cobalah untuk menghindari menulis di luar batas.

Udo Klein
sumber
ok, ini persis apa yang saya takuti. Saya akan 'mencoba untuk menghindari menulis di luar batas' tetapi, melihat apa yang telah saya lakukan beberapa bulan terakhir, saya pasti masih akan banyak melakukannya. Bagaimana kalian bisa begitu baik dalam pemrograman tanpa cara yang aman untuk berlatih?
ChrisD
3
Siapa bilang ada yang aman;)
Udo Klein
7

Tidak menjalankan program Anda sebagai root atau pengguna istimewa lainnya tidak akan membahayakan sistem Anda, jadi umumnya ini adalah ide yang bagus.

Dengan menulis data ke beberapa lokasi memori acak Anda tidak akan secara langsung "merusak" program lain yang berjalan di komputer Anda karena setiap proses berjalan di ruang memori itu sendiri.

Jika Anda mencoba mengakses memori apa pun yang tidak dialokasikan untuk proses Anda, sistem operasi akan menghentikan program Anda dari mengeksekusi dengan kesalahan segmentasi.

Jadi secara langsung (tanpa menjalankan sebagai root dan langsung mengakses file seperti / dev / mem) tidak ada bahaya bahwa program Anda akan mengganggu program lain yang berjalan pada sistem operasi Anda.

Namun demikian - dan mungkin inilah yang Anda dengar dalam hal bahaya - dengan secara acak menulis data acak ke lokasi memori acak, Anda yakin dapat merusak apa pun yang dapat Anda rusak.

Misalnya program Anda mungkin ingin menghapus file tertentu yang diberikan oleh nama file yang disimpan di suatu tempat di program Anda. Jika secara tidak sengaja Anda hanya menimpa lokasi tempat nama file disimpan, Anda mungkin akan menghapus file yang sangat berbeda.

mikyra
sumber
1
Jika Anda sedang berjalan sebagai root (atau beberapa pengguna istimewa lainnya), meskipun, hati-hati. Buffer dan array overruns adalah exploit malware yang umum.
John Bode
sebenarnya akun yang saya gunakan untuk semua komputasi harian saya bukan akun administrator (saya menggunakan terminologi OSX karena itu adalah sistem saya). Apakah Anda bermaksud memberi tahu saya bahwa saya tidak mungkin merusak sesuatu dengan mencoba mengatur lokasi memori APA PUN? Itu sebenarnya berita bagus!
ChrisD
Seperti yang telah disebutkan sebelumnya kerusakan terburuk yang dapat Anda lakukan secara tidak sengaja adalah bahaya terburuk yang dapat Anda lakukan sebagai pengguna. Jika Anda ingin 100% yakin tidak menghancurkan data Anda, Anda mungkin ingin menambahkan akun lain ke komputer Anda dan bereksperimen dengan itu.
mikyra
1
@mikyra: Itu benar hanya jika mekanisme perlindungan sistem 100% efektif. Keberadaan malware menunjukkan bahwa Anda tidak selalu dapat mengandalkan itu. (Saya tidak ingin menyarankan bahwa itu perlu dicemaskan; itu mungkin, tetapi tidak mungkin, bahwa suatu program dapat secara tidak sengaja mengeksploitasi celah keamanan yang sama yang dieksploitasi oleh malware.)
Keith Thompson
1
Daftar di sini termasuk: Menjalankan kode dari sumber yang tidak dipercaya. Cukup mengklik tombol OK pada sembulan firewall apa pun tanpa membaca apa artinya atau mematikannya sepenuhnya jika koneksi jaringan yang diinginkan tidak dapat dibuat. Menambal binari dengan retasan terbaru dari sumber yang meragukan. Ini bukan kesalahan lemari besi jika pemiliknya akan secara sukarela mengundang pencuri dengan kedua tangan dan pintu benteng yang kuat terbuka lebar.
mikyra
4

NSArrays di Objective-C diberi blok memori tertentu. Melebihi batas array berarti Anda akan mengakses memori yang tidak ditetapkan ke array. Ini berarti:

  1. Memori ini dapat memiliki nilai apa pun. Tidak ada cara untuk mengetahui apakah data tersebut valid berdasarkan pada tipe data Anda.
  2. Memori ini dapat berisi informasi sensitif seperti kunci pribadi atau kredensial pengguna lainnya.
  3. Alamat memori mungkin tidak valid atau dilindungi.
  4. Memori dapat memiliki nilai yang berubah karena sedang diakses oleh program lain atau utas.
  5. Hal-hal lain menggunakan ruang alamat memori, seperti port yang dipetakan memori.
  6. Menulis data ke alamat memori yang tidak dikenal dapat membuat crash program Anda, menimpa ruang memori OS, dan umumnya menyebabkan matahari meledak.

Dari aspek program Anda, Anda selalu ingin tahu kapan kode Anda melebihi batas array. Ini dapat menyebabkan nilai yang tidak diketahui dikembalikan, menyebabkan aplikasi Anda mogok atau memberikan data yang tidak valid.

Richard Brown
sumber
NSArraysmemiliki pengecualian di luar batas. Dan pertanyaan ini sepertinya tentang C array.
DrummerB
Maksudku memang array C. Saya tahu ada NSArray, tetapi untuk sekarang sebagian besar latihan saya di C
ChrisD
4

Anda mungkin ingin mencoba menggunakan memcheckalat di Valgrind ketika Anda menguji kode Anda - itu tidak akan menangkap pelanggaran batas array individu dalam bingkai tumpukan, tetapi harus menangkap berbagai jenis masalah memori lainnya, termasuk yang akan menyebabkan masalah lebih halus, lebih luas masalah di luar ruang lingkup fungsi tunggal.

Dari manual:

Memcheck adalah pendeteksi kesalahan memori. Itu dapat mendeteksi masalah-masalah berikut yang umum dalam program C dan C ++.

  • Mengakses memori Anda tidak seharusnya, misalnya overrunning dan underrunning heap blocks, overrunning bagian atas stack, dan mengakses memori setelah itu dibebaskan.
  • Menggunakan nilai yang tidak ditentukan, yaitu nilai yang belum diinisialisasi, atau yang telah diturunkan dari nilai yang tidak ditentukan lainnya.
  • Membebaskan memori tumpukan yang salah, seperti tumpukan tumpukan pembekuan ganda, atau penggunaan malloc / baru / baru [] yang tidak sesuai dengan bebas / hapus / hapus []
  • Tumpang tindih src dan pointer dst dalam fungsi memcpy dan terkait.
  • Memori bocor.

ETA: Meskipun, seperti jawaban Kaz mengatakan, itu bukan obat mujarab, dan tidak selalu memberikan hasil yang paling membantu, terutama ketika Anda menggunakan pola akses yang menarik .

Aesin
sumber
Saya menduga Analyzer XCode akan menemukan sebagian besar dari itu? dan pertanyaan saya bukan bagaimana menemukan bug ini, tetapi jika menjalankan program yang masih memiliki bug ini berbahaya bagi memori yang tidak dialokasikan untuk program saya. Saya harus menjalankan program untuk melihat bug terjadi
ChrisD
3

Jika Anda pernah melakukan pemrograman tingkat sistem atau pemrograman sistem tertanam, hal-hal yang sangat buruk dapat terjadi jika Anda menulis ke lokasi memori acak. Sistem yang lebih lama dan banyak pengontrol mikro menggunakan memori yang dipetakan IO, jadi menulis ke lokasi memori yang memetakan ke register periferal dapat mendatangkan malapetaka, terutama jika itu dilakukan secara tidak sinkron.

Contohnya adalah pemrograman memori flash. Mode pemrograman pada chip memori diaktifkan dengan menulis urutan nilai tertentu ke lokasi tertentu di dalam kisaran alamat chip. Jika proses lain adalah menulis ke lokasi lain dalam chip saat itu sedang berlangsung, itu akan menyebabkan siklus pemrograman gagal.

Dalam beberapa kasus, perangkat keras akan membungkus alamat (sebagian besar bit / byte alamat diabaikan) sehingga penulisan ke alamat di luar akhir ruang alamat fisik sebenarnya akan menghasilkan data yang ditulis tepat di tengah-tengah hal.

Dan akhirnya, CPU yang lebih lama seperti MC68000 dapat dikunci hingga hanya reset perangkat keras yang dapat membuatnya berjalan kembali. Belum bekerja pada mereka selama beberapa dekade tapi saya percaya itu ketika mengalami kesalahan bus (memori tidak ada) ketika mencoba menangani pengecualian, itu hanya akan berhenti sampai reset perangkat keras ditegaskan.

Rekomendasi terbesar saya adalah steker terang-terangan untuk suatu produk, tetapi saya tidak memiliki kepentingan pribadi di dalamnya dan saya tidak berafiliasi dengan mereka dengan cara apa pun - tetapi berdasarkan beberapa dekade pemrograman C dan sistem tertanam di mana keandalan sangat penting, PC Gimpel Lint tidak hanya akan mendeteksi kesalahan semacam itu, itu akan membuat programmer C / C ++ yang lebih baik keluar dari Anda dengan terus-menerus mengomeli Anda tentang kebiasaan buruk.

Saya juga merekomendasikan membaca standar pengkodean MISRA C, jika Anda dapat mengambil salinan dari seseorang. Saya belum melihat yang baru-baru ini tetapi di masa lalu mereka memberikan penjelasan yang baik tentang mengapa Anda harus / tidak harus melakukan hal-hal yang mereka liput.

Entah tentang Anda, tetapi sekitar ke-2 atau ke-3 saya mendapatkan coredump atau hangup dari aplikasi apa pun, pendapat saya tentang perusahaan apa pun yang menghasilkannya turun setengahnya. Kali ke-4 atau ke-5 dan apa pun paketnya menjadi rak buku dan saya menggerakkan pasak kayu melalui bagian tengah paket / cakram itu masuk hanya untuk memastikan tidak pernah kembali menghantui saya.

Dan Haynes
sumber
Bergantung pada sistem, pembacaan di luar jangkauan juga dapat memicu perilaku yang tidak dapat diprediksi, atau mereka mungkin jinak, meskipun perilaku perangkat keras yang jinak pada beban di luar jangkauan tidak menyiratkan perilaku kompiler yang jinak.
supercat
2

Saya bekerja dengan kompiler untuk chip DSP yang sengaja menghasilkan kode yang mengakses satu melewati akhir array keluar dari kode C yang tidak!

Ini karena loop disusun sehingga akhir iterasi mengambil beberapa data untuk iterasi berikutnya. Jadi datum yang diambil pada akhir iterasi terakhir tidak pernah benar-benar digunakan.

Menulis kode C seperti itu memanggil perilaku yang tidak terdefinisi, tetapi itu hanya formalitas dari dokumen standar yang berkaitan dengan portabilitas maksimal.

Lebih sering tidak, program yang mengakses di luar batas tidak dioptimalkan secara cerdik. Itu hanya buggy. Kode mengambil beberapa nilai sampah dan, tidak seperti loop dioptimalkan dari kompiler yang disebutkan di atas, kode kemudian menggunakan nilai dalam perhitungan berikutnya, sehingga merusak mereka.

Perlu menangkap bug seperti itu, dan karenanya layak membuat perilaku tidak terdefinisi hanya untuk alasan itu saja: sehingga run-time dapat menghasilkan pesan diagnostik seperti "array overrun pada baris 42 dari main.c".

Pada sistem dengan memori virtual, sebuah array dapat dialokasikan sedemikian rupa sehingga alamat yang mengikutinya berada di area memori virtual yang tidak dipetakan. Akses kemudian akan mengebom program.

Sebagai tambahan, perhatikan bahwa dalam C kita diizinkan untuk membuat pointer yang melewati akhir array. Dan pointer ini harus membandingkan lebih besar dari pointer apa pun dengan interior array. Ini berarti bahwa implementasi C tidak dapat menempatkan array tepat di akhir memori, di mana satu alamat plus akan membungkus dan terlihat lebih kecil dari alamat lain dalam array.

Namun demikian, akses ke nilai yang tidak diinisialisasi atau keluar dari batas kadang-kadang merupakan teknik optimasi yang valid, bahkan jika tidak portabel secara maksimal. Ini adalah contohnya mengapa alat Valgrind tidak melaporkan akses ke data yang tidak diinisialisasi ketika akses tersebut terjadi, tetapi hanya ketika nilainya kemudian digunakan dalam beberapa cara yang dapat mempengaruhi hasil program. Anda mendapatkan diagnostik seperti "cabang bersyarat dalam xxx: nnn tergantung pada nilai yang tidak diinisialisasi" dan terkadang sulit untuk melacak dari mana asalnya. Jika semua akses semacam itu langsung terjebak, akan ada banyak kesalahan positif yang timbul dari kode yang dioptimalkan kompiler serta kode yang dioptimalkan dengan tangan dengan benar.

Omong-omong, saya bekerja dengan beberapa codec dari vendor yang mengeluarkan kesalahan ini ketika porting ke Linux dan berjalan di bawah Valgrind. Tetapi vendor meyakinkan saya bahwa hanya beberapa bitnilai yang digunakan sebenarnya berasal dari memori yang tidak diinisialisasi, dan bit-bit itu dengan hati-hati dihindari oleh logika .. Hanya bit yang baik dari nilai yang digunakan dan Valgrind tidak memiliki kemampuan untuk melacak ke bit individual. Materi yang tidak diinisialisasi berasal dari membaca sepatah kata melewati akhir bit stream data yang dikodekan, tetapi kode tahu berapa banyak bit dalam aliran dan tidak akan menggunakan lebih banyak bit daripada yang sebenarnya. Karena akses di luar akhir bit stream array tidak menyebabkan kerusakan pada arsitektur DSP (tidak ada memori virtual setelah array, tidak ada port yang dipetakan memori, dan alamat tidak membungkus) itu adalah teknik optimasi yang valid.

"Perilaku tidak terdefinisi" tidak terlalu berarti, karena menurut ISO C, cukup menyertakan header yang tidak didefinisikan dalam standar C, atau memanggil fungsi yang tidak didefinisikan dalam program itu sendiri atau standar C, adalah contoh dari tidak terdefinisi tingkah laku. Perilaku tidak terdefinisi tidak berarti "tidak didefinisikan oleh siapa pun di planet ini" hanya "tidak didefinisikan oleh standar ISO C". Namun tentu saja, terkadang perilaku tidak terdefinisi benar - benar tidak didefinisikan oleh siapa pun.

Kaz
sumber
Selain itu, asalkan ada setidaknya satu program yang proses implementasi tertentu benar meskipun secara nominal memajaki semua batasan implementasi yang diberikan dalam Standar, bahwa implementasi dapat berperilaku sewenang-wenang ketika memasukkan program lain yang bebas dari pelanggaran kendala dan masih " sesuai ". Akibatnya, 99,999% dari program C (apa pun selain "satu program" platform) bergantung pada perilaku di mana Standar tidak memaksakan persyaratan.
supercat
1

Selain program Anda sendiri, saya rasa Anda tidak akan merusak apa pun, dalam kasus terburuk Anda akan mencoba membaca atau menulis dari alamat memori yang sesuai dengan halaman yang tidak ditentukan oleh kernel untuk proses Anda, menghasilkan pengecualian yang tepat dan terbunuh (maksud saya, proses Anda).

jbgs
sumber
3
..Apa? Bagaimana dengan menimpa memori dalam proses Anda sendiri yang digunakan untuk menyimpan beberapa variabel yang digunakan nanti ... yang sekarang secara misterius mengubah nilainya! Bug-bug itu sangat menyenangkan untuk dilacak, saya yakinkan Anda. Segfault akan menjadi hasil terbaik . -1
Ed S.
2
Maksud saya dia tidak akan "merusak" proses lain, selain programnya sendiri;)
jbgs
Saya memang tidak peduli jika saya merusak program saya sendiri. Saya baru belajar, program ini jelas salah pula jika saya mengakses sesuatu di luar jangkauan array saya. Saya semakin khawatir tentang risiko merusak sesuatu yang lain saat
men
Masalahnya adalah: dapatkah saya yakin jika saya mencoba mengakses memori yang tidak ditugaskan kepada saya, bahwa proses saya akan terbunuh? (berada di OSX)
ChrisD
3
Bertahun-tahun lalu, saya dulunya adalah seorang programmer C yang ceroboh. Saya mengakses array di luar batas mereka ratusan kali. Selain proses saya terbunuh oleh sistem operasi, tidak ada yang terjadi.
jbgs