Apakah kerusakan memori merupakan masalah umum dalam program besar yang ditulis dalam bahasa assembly?

Jan 21 2021

Bug kerusakan memori selalu menjadi masalah umum dalam program dan proyek C besar. Itu adalah masalah di 4.3BSD saat itu, dan masih menjadi masalah sampai sekarang. Tidak peduli seberapa hati-hati program itu ditulis, jika itu cukup besar, sering kali mungkin untuk menemukan bug baca atau tulis lain yang tidak terikat dalam kode.

Tetapi ada suatu masa ketika program besar, termasuk sistem operasi, ditulis dalam rakitan, bukan C. Apakah bug kerusakan memori merupakan masalah umum dalam program rakitan besar? Dan bagaimana jika dibandingkan dengan program C?

Jawaban

53 Jean-FrançoisFabre Jan 21 2021 at 17:23

Pengkodean dalam perakitan itu brutal.

Penunjuk nakal

Bahasa assembly lebih bergantung pada pointer (melalui register alamat) sehingga Anda bahkan tidak dapat mengandalkan compiler atau alat analisis statis untuk memperingatkan Anda tentang kerusakan memori / buffer overruns dibandingkan dengan C.

Misalnya di C, kompilator yang baik mungkin mengeluarkan peringatan di sana:

 char x[10];
 x[20] = 'c';

Itu terbatas. Segera setelah array meluruh menjadi pointer, pemeriksaan seperti itu tidak dapat dilakukan, tetapi itu adalah permulaan.

Dalam perakitan, tanpa alat biner run-time atau eksekusi formal yang tepat, Anda tidak dapat mendeteksi kesalahan semacam itu.

Rogue (kebanyakan alamat) register

Faktor lain yang memberatkan untuk perakitan adalah bahwa pemeliharaan register dan konvensi pemanggilan rutin tidak standar / dijamin.

Jika rutin dipanggil dan tidak menyimpan register tertentu karena kesalahan, maka rutinitas kembali ke pemanggil dengan register yang dimodifikasi (di samping register "awal" yang diketahui dibuang saat keluar), dan pemanggil tidak mengharapkan itu, yang mengarah pada membaca / menulis ke alamat yang salah. Misalnya dalam kode 68k:

    move.b  d0,(a3)+
    bsr  a_routine
    move.b  d0,(a3)+   ; memory corruption, a3 has changed unexpectedly
    ...

a_routine:
    movem.l a0-a2,-(a7)
    ; do stuff
    lea some_table(pc),a3    ; change a3 if some condition is met
    movem.l (a7)+,a0-a2   ; the routine forgot to save a3 !
    rts

Menggunakan rutinitas yang ditulis oleh orang lain yang tidak menggunakan konvensi penyimpanan register yang sama dapat menyebabkan masalah yang sama. Saya biasanya menyimpan semua register sebelum menggunakan rutinitas orang lain.

Di sisi lain, kompilator menggunakan stack atau passing parameter register standar, menangani variabel lokal menggunakan stack / device lain, mempertahankan register jika diperlukan, dan semuanya koheren dalam keseluruhan program, dijamin oleh compiler (kecuali ada bug, dari kursus)

Mode pengalamatan nakal

Saya memperbaiki banyak pelanggaran memori di game Amiga kuno. Menjalankannya di lingkungan virtual dengan MMU yang diaktifkan terkadang memicu kesalahan baca / tulis di alamat palsu lengkap. Sebagian besar waktu baca / tulis tersebut tidak berpengaruh karena pembacaan mengembalikan 0 dan penulisan berjalan di hutan, tetapi tergantung pada konfigurasi memori, hal itu dapat memiliki konsekuensi yang buruk.

Ada juga kasus kesalahan pengalamatan. Saya melihat hal-hal seperti:

 move.l $40000,a0

bukannya langsung

 move.l #$40000,a0

dalam hal ini, register alamat berisi apa yang ada di $40000(mungkin sampah) dan bukan $40000alamatnya. Hal ini menyebabkan kerusakan memori yang dahsyat dalam beberapa kasus. Gim biasanya akhirnya melakukan tindakan yang tidak berfungsi di tempat lain tanpa memperbaikinya sehingga gim tersebut bekerja dengan baik sebagian besar waktu. Tetapi ada kalanya game harus diperbaiki dengan benar untuk memulihkan perilaku yang tepat.

Di C, menyesatkan nilai untuk pointer mengarah ke peringatan.

(Kami menyerah pada game seperti "Wicked" yang memiliki semakin banyak kerusakan grafis, semakin Anda mahir dalam level, tetapi juga tergantung pada cara Anda melewati level dan urutannya ...)

Ukuran data nakal

Dalam perakitan, tidak ada tipe. Artinya jika saya lakukan

move.w #$4000,d0           ; copy only 16 bits
move.l #1,(a0,d0.l)    ; indexed write on d1, long

yang d0mendaftar hanya mendapatkan setengah dari data berubah. Mungkin yang saya inginkan, mungkin tidak. Kemudian jika d0berisi nol pada 32-16 bit yang paling signifikan, kode melakukan apa yang diharapkan, jika tidak ia menambahkan a0dan d0(jangkauan penuh) dan tulisan yang dihasilkan adalah "di hutan". Perbaikannya adalah:

move.l #1,(a0,d0.w)    ; indexed write on d1, long

Tetapi kemudian jika d0> $7FFFmelakukan sesuatu yang salah juga, karena d0dianggap negatif maka (tidak demikian halnya dengan d0.l). Jadi d0perlu ekstensi tanda atau masking ...

Kesalahan ukuran tersebut dapat dilihat pada kode C, misalnya ketika menetapkan ke shortvariabel (yang memotong hasilnya) tetapi meskipun demikian Anda sering mendapatkan hasil yang salah, bukan masalah fatal seperti di atas (yaitu: jika Anda tidak tidak berbohong kepada kompiler dengan memaksa tipe cast yang salah)

Assembler tidak memiliki tipe, tetapi assembler yang baik memungkinkan untuk menggunakan struktur ( STRUCTkata kunci) yang memungkinkan untuk sedikit meninggikan kode dengan secara otomatis menghitung offset struktur. Tetapi pembacaan ukuran yang buruk bisa menjadi bencana tidak peduli Anda menggunakan struct / offset yang ditentukan atau tidak

move.w  the_offset(a0),d0

dari pada

move.l  the_offset(a0),d0

tidak dicentang, dan memberi Anda data yang salah d0. Pastikan Anda minum kopi yang cukup saat membuat kode, atau hanya menulis dokumentasi saja ...

Penyelarasan data nakal

Assembler biasanya memperingatkan tentang kode yang tidak selaras, tetapi bukan pada pointer yang tidak selaras (karena pointer tidak memiliki tipe), yang dapat memicu kesalahan bus.

Bahasa tingkat tinggi menggunakan jenis dan menghindari sebagian besar kesalahan tersebut dengan melakukan perataan / pengisi (kecuali, sekali lagi, berbohong).

Namun, Anda dapat menulis program perakitan dengan sukses. Dengan menggunakan metodologi ketat untuk parameter yang melewati / menyimpan register dan dengan mencoba menutupi 100% kode Anda dengan tes, dan debugger (simbolik atau tidak, ini masih kode yang telah Anda tulis). Itu tidak akan menghapus semua bug potensial, terutama yang disebabkan oleh data input yang salah, tetapi itu akan membantu.

24 jackbochsler Jan 22 2021 at 05:41

Saya menghabiskan sebagian besar karir saya menulis assembler, solo, tim kecil dan tim besar (Cray, SGI, Sun, Oracle). Saya bekerja pada sistem tertanam, OS, VM, dan pemuat bootstrap. Kerusakan memori jarang menjadi masalah. Kami merekrut orang-orang cerdas, dan mereka yang gagal dikelola menjadi pekerjaan berbeda yang lebih sesuai dengan keterampilan mereka.

Kami juga menguji secara fanatik - baik di level unit maupun level sistem. Kami memiliki pengujian otomatis yang berjalan terus-menerus baik pada simulator maupun perangkat keras nyata.

Menjelang akhir karier saya, saya mewawancarai sebuah perusahaan dan saya bertanya tentang bagaimana mereka melakukan pengujian otomatis. Tanggapan mereka tentang "Apa?!?" hanya itu yang perlu saya dengar, saya mengakhiri wawancara.

19 RETRAC Jan 21 2021 at 23:10

Kesalahan bodoh sederhana berlimpah dalam perakitan, tidak peduli seberapa hati-hati Anda. Ternyata kompiler bodoh untuk bahasa tingkat tinggi yang didefinisikan dengan buruk (seperti C) membatasi sejumlah besar kemungkinan kesalahan karena tidak valid secara semantik atau sintaksis. Kesalahan dengan satu penekanan tombol ekstra atau terlupakan jauh lebih mungkin ditolak untuk dikompilasi daripada yang harus dirakit. Konstruksi yang dapat Anda ekspresikan secara valid dalam perakitan yang tidak masuk akal karena Anda melakukan semuanya dengan salah cenderung tidak diterjemahkan menjadi sesuatu yang diterima sebagai C yang valid. Dan karena Anda beroperasi pada tingkat yang lebih tinggi, Anda lebih cenderung untuk memicingkan mata dan berkata "ya?" dan menulis ulang monster yang baru saja Anda tulis.

Jadi pengembangan dan debugging assembly memang sangat sulit untuk dimaafkan. Tapi kebanyakan kesalahan tersebut melanggar hal-hal yang sulit , dan akan muncul dalam pengembangan dan debugging. Saya akan membahayakan tebakan terpelajar bahwa, jika para pengembang mengikuti arsitektur dasar yang sama dan praktik pengembangan yang sama, produk akhirnya harus sama kuatnya. Jenis kesalahan yang ditangkap oleh kompilator dapat ditangkap dengan praktik pengembangan yang baik, dan jenis kesalahan yang tidak ditangkap oleh penyusun mungkin atau mungkin tidak tertangkap dengan praktik semacam itu. Akan membutuhkan waktu lebih lama untuk mencapai level yang sama.

14 WalterMitty Jan 23 2021 at 02:48

Saya menulis pengumpul sampah asli untuk MDL, bahasa mirip Lisp, pada tahun 1971-72. Itu merupakan tantangan bagi saya saat itu. Itu tertulis di MIDAS, assembler untuk PDP-10 yang menjalankan ITS.

Menghindari kerusakan memori adalah nama permainan dalam proyek itu. Seluruh tim takut demo yang berhasil terhenti dan terbakar saat pemulung dipanggil. Dan saya tidak punya rencana debugging yang bagus untuk kode itu. Saya melakukan lebih banyak pemeriksaan meja daripada yang pernah saya lakukan sebelumnya atau sejak itu. Hal-hal seperti memastikan tidak ada kesalahan tiang pagar. Memastikan bahwa ketika sekelompok vektor dipindahkan, target tidak mengandung non-sampah. Berulang kali, menguji asumsi saya.

Saya tidak pernah menemukan bug dalam kode itu, kecuali yang ditemukan oleh pemeriksaan meja. Setelah kami siaran langsung, tidak ada yang muncul selama saya menonton.

Saya hanya tidak sepintar saya lima puluh tahun yang lalu. Saya tidak bisa melakukan hal seperti itu hari ini. Dan sistem saat ini ribuan kali lebih besar dari MDL sebelumnya.

7 Raffzahn Jan 22 2021 at 00:00

Bug kerusakan memori selalu menjadi masalah umum dalam program C besar [...] Tapi ada saat ketika program besar, termasuk sistem operasi, ditulis dalam rakitan, bukan C.

Anda tahu bahwa ada bahasa lain yang sudah cukup umum sejak awal? Seperti COBOL, FORTRAN atau PL / 1?

Apakah bug kerusakan memori merupakan masalah umum dalam program perakitan besar?

Ini tentu saja tergantung pada banyak faktor, seperti

  • Assembler digunakan, karena program assembler yang berbeda menawarkan tingkat dukungan pemrograman yang berbeda.
  • struktur program, karena program yang sangat besar mengikuti struktur yang dapat diperiksa
  • modularisasi, dan antarmuka yang jelas
  • jenis program yang ditulis, karena tidak setiap tugas membutuhkan pengotak-atik penunjuk
  • gaya praktik terbaik

Assembler yang baik tidak hanya memastikan bahwa data sejajar, tetapi juga menawarkan alat untuk menangani tipe data kompleks, struktur dan sejenisnya secara abstrak, mengurangi kebutuhan untuk menghitung pointer 'secara manual'.

Assembler yang digunakan untuk proyek serius apa pun selalu merupakan assembler makro (* 1), sehingga mampu merangkum operasi primitif ke dalam instruksi makro tingkat yang lebih tinggi, memungkinkan pemrograman yang lebih berpusat pada aplikasi sambil menghindari banyak kesulitan penanganan penunjuk (* 2).

Jenis program juga cukup berpengaruh. Aplikasi biasanya terdiri dari berbagai modul, banyak di antaranya dapat ditulis hampir atau lengkap tanpa (atau hanya dikontrol) penggunaan penunjuk. Sekali lagi, penggunaan alat yang disediakan oleh assembler adalah kunci untuk mengurangi kode yang salah.

Berikutnya adalah praktik terbaik - yang sejalan dengan banyak praktik sebelumnya. Sederhananya, jangan menulis program / modul yang membutuhkan banyak register basis, yang menyerahkan sebagian besar memori alih-alih struktur permintaan khusus dan seterusnya ...

Tetapi praktik terbaik sudah dimulai sejak dini dan dengan hal-hal yang tampaknya sederhana. Ambil saja contoh CPU primitif (maaf) seperti 6502 yang mungkin memiliki satu set tabel, semua disesuaikan dengan batas halaman untuk kinerja. Saat memuat alamat salah satu tabel ini ke penunjuk halaman nol untuk akses yang diindeks, penggunaan alat yang dimaksudkan assembler akan digunakan

     LDA   #<Table
     STA   Pointer

Beberapa program yang saya lihat malah pergi

     LDA   #0
     STA   Pointer

(atau lebih buruk, jika pada 65C02)

     STZ   Pointer

Argumen yang biasa adalah 'Tapi itu selaras'. Apakah itu? Bisakah itu dijamin untuk semua iterasi di masa mendatang? Bagaimana dengan suatu hari ketika ruang alamat semakin sempit dan mereka perlu dipindahkan ke alamat yang tidak selaras? Banyak kesalahan besar (alias sulit ditemukan) yang bisa diharapkan.

Jadi, Praktik terbaik kembali membawa kita kembali menggunakan Assembler dan semua alat yang ditawarkannya.

Jangan mencoba bermain sebagai Assembler dan bukan sebagai Assembler - biarkan dia melakukan pekerjaannya untuk Anda.

Dan kemudian ada runtime, sesuatu yang berlaku untuk semua bahasa tetapi sering dilupakan. Selain hal-hal seperti pemeriksaan tumpukan atau pemeriksaan batas pada parameter, salah satu cara paling efektif untuk menangkap kesalahan penunjuk adalah dengan mengunci halaman memori terakhir dan pertama dari penulisan dan baca (* 3). Ini tidak hanya menangkap semua kesalahan penunjuk nol yang dicintai, tetapi juga semua angka positif atau negatif rendah yang sering kali merupakan hasil dari beberapa pengindeksan sebelumnya yang salah. Tentu, Waktu proses selalu menjadi pilihan terakhir, tetapi yang ini mudah.

Di atas segalanya, mungkin alasan yang paling relevan adalah

  • ISA mesin

dalam mengurangi kemungkinan kerusakan memori dengan mengurangi kebutuhan untuk menangani petunjuk sama sekali.

Beberapa struktur CPU hanya memerlukan lebih sedikit operasi penunjuk (langsung) daripada yang lain. Ada kesenjangan besar antara arsitektur yang menyertakan operasi memori ke memori vs. arsitektur yang tidak, seperti arsitektur load / store berbasis akumulator. Secara inheren memerlukan penanganan penunjuk untuk sesuatu yang lebih besar dari satu elemen (byte / kata).

Misalnya untuk mentransfer bidang, katakanlah nama pelanggan dari sekitar dalam memori, a / 360 menggunakan operasi MVC tunggal dengan alamat dan panjang transfer yang dihasilkan oleh assembler dari definisi data, sedangkan arsitektur muat / penyimpanan, dirancang untuk menangani setiap byte terpisah, harus mengatur pointer dan panjang dalam register dan loop di sekitar elemen tunggal yang bergerak.

Karena operasi semacam itu cukup umum, potensi kesalahan yang dihasilkan juga umum terjadi. Atau, dengan cara yang lebih umum dapat dikatakan bahwa:

Program untuk prosesor CISC biasanya tidak terlalu rentan terhadap kesalahan daripada yang ditulis untuk mesin RISC.

Tentu saja dan seperti biasa, semuanya bisa kacau oleh pemrograman yang buruk.

Dan bagaimana jika dibandingkan dengan program C?

Hampir sama - atau lebih baik, C adalah HLL yang setara dengan ISA CPU paling primitif, jadi apa pun yang menawarkan instruksi tingkat yang lebih tinggi akan lebih baik.

C pada dasarnya adalah bahasa RISCy. Operasi yang disediakan dikurangi seminimal mungkin, yang sejalan dengan kemampuan minimum untuk memeriksa operasi yang tidak diinginkan. Menggunakan pointer yang tidak dicentang tidak hanya standar tetapi diperlukan untuk banyak operasi, membuka banyak kemungkinan kerusakan memori.

Bandingkan dengan HLL seperti ADA, di sini hampir tidak mungkin untuk membuat malapetaka penunjuk - kecuali jika itu dimaksudkan dan secara eksplisit dinyatakan sebagai opsi. Bagian yang baik darinya adalah (seperti dengan ISA sebelumnya) karena tipe data yang lebih tinggi dan penanganannya dengan cara yang aman.


Untuk bagian pengalaman, saya melakukan sebagian besar kehidupan profesional saya (> 30 tahun) dalam proyek Perakitan, dengan seperti 80% Mainframe (/ 370) 20% Mikro (kebanyakan 8080 / x86) - ditambah lebih banyak pribadi :) Pemrograman mainframe mencakup proyek sebesar 2+ juta LOC (hanya instruksi) sedangkan proyek mikro menyimpan sekitar 10-20 ribu LOC.


* 1 - Tidak, sesuatu yang menawarkan penggantian bagian teks dengan teks yang dibuat sebelumnya adalah yang terbaik dari beberapa preprosesor tekstual, tetapi bukan assembler makro. Perakit makro adalah alat meta untuk membuat bahasa yang dibutuhkan untuk proyek. Ini menawarkan alat untuk memanfaatkan informasi yang dikumpulkan assembler tentang sumber (ukuran bidang, jenis bidang, dan banyak lagi) serta struktur kontrol untuk merumuskan penanganan, yang digunakan untuk menghasilkan kode yang sesuai.

* 2 - Sangat mudah untuk meratapi bahwa C tidak cocok dengan kapabilitas makro yang serius, C tidak hanya menghilangkan kebutuhan akan banyak konstruksi yang tidak jelas, tetapi juga memungkinkan banyak kemajuan dengan memperluas bahasa tanpa perlu menulis yang baru.

* 3 - Secara pribadi saya lebih suka membuat halaman 0 hanya menulis yang dilindungi dan mengisi 256 byte pertama dengan nol biner. Dengan cara itu semua penulisan pointer nol (atau rendah) masih menghasilkan kesalahan mesin, tetapi membaca dari pointer nol kembali, tergantung pada jenisnya, byte / halfword / word / doublewort yang berisi nol - baik, atau string-nol :) Saya tahu, itu malas, tetapi itu membuat hidup jauh lebih mudah jika seseorang harus tidak bekerja sama dengan kode orang lain. Juga halaman yang tersisa dapat digunakan untuk nilai konstan yang berguna seperti pointer ke berbagai sumber global, string ID, konten bidang konstan, dan tabel terjemahan.

6 waltinator Jan 22 2021 at 09:17

Saya telah menulis mod OS dalam perakitan di CDC G-21, Univac 1108, DECSystem-10, DECSystem-20, semua sistem 36 bit, ditambah 2 perakit IBM 1401.

Ada "kerusakan memori", sebagian besar sebagai entri pada daftar "Hal-hal yang Tidak Dapat Dilakukan".

Pada Univac 1108 saya menemukan kesalahan perangkat keras di mana pengambilan setengah kata pertama (alamat penangan interupsi) setelah interupsi perangkat keras akan mengembalikan semua 1s, alih-alih konten alamat. Pergi ke gulma, dengan interupsi dinonaktifkan, tidak ada perlindungan memori. Berputar-putar, di mana ia berhenti tidak ada yang tahu.

5 Peter-ReinstateMonica Jan 22 2021 at 19:31

Anda membandingkan apel dan pir. Bahasa tingkat tinggi ditemukan karena program mencapai ukuran yang tidak dapat diatur oleh assembler. Contoh: "V1 memiliki 4.501 baris kode assembly untuk kernel, inisialisasi, dan cangkangnya. Dari jumlah tersebut, 3.976 akun untuk kernel, dan 374 untuk shell." (Dari jawaban ini .)

Itu. V1. Kulit. Seandainya. 347. Garis. Dari. Kode.

Bash hari ini mungkin memiliki 100.000 baris kode (wc di atas repo menghasilkan 170k), tidak termasuk perpustakaan pusat seperti readline dan lokalisasi. Bahasa tingkat tinggi digunakan sebagian untuk portabilitas tetapi juga karena hampir tidak mungkin untuk menulis program dengan ukuran saat ini di assembler. Bukan hanya lebih rentan terhadap kesalahan - ini hampir tidak mungkin.

4 supercat Jan 22 2021 at 03:45

Saya tidak berpikir kerusakan memori umumnya lebih merupakan masalah dalam bahasa assembly daripada bahasa lain yang menggunakan operasi langganan array yang tidak dicentang, saat membandingkan program yang melakukan tugas serupa. Saat menulis kode assembly yang benar mungkin memerlukan perhatian pada detail di luar yang akan relevan dalam bahasa seperti C, beberapa aspek bahasa assembly sebenarnya lebih aman daripada C. Dalam bahasa assembly, jika kode melakukan urutan pemuatan dan penyimpanan, assembler akan menghasilkan instruksi pemuatan dan penyimpanan dalam urutan yang diberikan tanpa mempertanyakan apakah semuanya diperlukan. Sebaliknya, di C, jika kompilator pintar seperti clang dipanggil dengan setelan pengoptimalan apa pun selain -O0dan diberikan sesuatu seperti:

extern char x[],y[];
int test(int index)
{
    y[0] = 1;
    if (x+2 == y+index)
        y[index] = 2;
    return y[0];
}

itu dapat menentukan bahwa nilai y[0]ketika returnpernyataan dieksekusi akan selalu 1, dan oleh karena itu tidak perlu memuat ulang nilainya setelah menulis ke y[index], meskipun satu-satunya keadaan yang ditentukan di mana penulisan ke indeks dapat terjadi adalah jika x[]dua byte, y[]terjadi untuk segera mengikutinya, dan indexnol, menyiratkan bahwa y[0]akan tetap memegang nomor 2.

3 phyrfox Jan 23 2021 at 23:33

Assembler membutuhkan pengetahuan yang lebih mendalam tentang perangkat keras yang Anda gunakan daripada bahasa lain seperti C atau Java. Sebenarnya, assembler telah digunakan di hampir semua hal mulai dari mobil terkomputerisasi pertama, sistem video game awal hingga tahun 1990-an, hingga perangkat Internet-of-Things yang kita gunakan saat ini.

Sementara C menawarkan keamanan tipe, itu masih tidak menawarkan langkah-langkah keamanan lain seperti pemeriksaan penunjuk kosong atau array terbatas (setidaknya, bukan tanpa kode tambahan). Sangat mudah untuk menulis program yang akan rusak dan terbakar serta program assembler lainnya.

Puluhan ribu video game yang ditulis dalam assembler, kompos untuk menulis demo kecil namun mengesankan dalam hanya beberapa kilobyte kode / data yang selama beberapa dekade sekarang, ribuan mobil masih menggunakan beberapa bentuk assembler hari ini, serta beberapa yang kurang dikenal sistem operasi (misalnya MenuetOS ). Anda mungkin memiliki lusinan atau bahkan ratusan hal di rumah Anda yang diprogram dalam assembler yang bahkan tidak Anda ketahui.

Masalah utama dengan pemrograman assembly adalah Anda perlu merencanakan lebih keras daripada yang Anda lakukan dalam bahasa seperti C. Sangat mungkin untuk menulis program bahkan dengan 100k baris kode di assembler tanpa satu bug, dan juga memungkinkan untuk menulis sebuah program dengan 20 baris kode yang memiliki 5 bug.

Masalahnya bukanlah alatnya, melainkan pemrogramnya. Saya akan mengatakan bahwa kerusakan memori adalah masalah umum dalam pemrograman awal secara umum. Ini tidak terbatas pada assembler, tetapi juga C (yang terkenal karena membocorkan memori dan mengakses rentang memori yang tidak valid), C ++, dan bahasa lain di mana Anda dapat langsung mengakses memori, bahkan BASIC (yang memiliki kemampuan untuk membaca / menulis I / tertentu O port pada CPU).

Bahkan dengan bahasa modern yang memiliki pengaman, kita akan melihat kesalahan pemrograman yang merusak game. Mengapa? Karena tidak ada perhatian yang cukup untuk mendesain aplikasi. Manajemen memori belum hilang, telah terselip di sudut yang lebih sulit untuk divisualisasikan, menyebabkan semua jenis kekacauan acak dalam kode modern.

Hampir setiap bahasa rentan terhadap berbagai jenis kerusakan memori jika digunakan secara tidak benar. Saat ini, masalah yang paling umum adalah kebocoran memori, yang lebih mudah dari sebelumnya secara tidak sengaja karena penutupan dan abstraksi.

Tidak adil untuk mengatakan bahwa assembler secara inheren lebih atau kurang merusak memori daripada bahasa lain, itu hanya mendapat reputasi buruk karena betapa menantangnya menulis kode yang tepat.

2 JohnDoty Jan 23 2021 at 02:12

Itu masalah yang sangat umum. Kompiler FORTRAN IBM untuk 1130 memiliki beberapa: yang saya ingat melibatkan kasus sintaks yang salah yang tidak terdeteksi. Pindah ke bahasa tingkat mesin yang lebih tinggi jelas tidak membantu: sistem Multics awal yang ditulis dalam PL / I sering macet. Saya pikir budaya dan teknik pemrograman lebih berkaitan dengan memperbaiki situasi ini daripada bahasa.

2 JohnDallman Jan 24 2021 at 21:26

Saya melakukan beberapa tahun pemrograman assembler, diikuti oleh beberapa dekade C. Program Assembler tampaknya tidak memiliki lebih banyak bug penunjuk yang buruk daripada C, tetapi alasan yang signifikan untuk itu adalah bahwa pemrograman assembler relatif lambat bekerja.

Tim tempat saya bergabung ingin menguji pekerjaan mereka setiap kali mereka menulis peningkatan fungsionalitas, yang biasanya setiap 10-20 instruksi assembler. Dalam bahasa tingkat yang lebih tinggi, Anda biasanya menguji setelah jumlah baris kode yang sama, yang memiliki lebih banyak fungsi. Itu trade off terhadap keamanan sebuah HLL.

Assembler berhenti digunakan untuk tugas pemrograman skala besar karena memberikan produktivitas yang lebih rendah, dan karena biasanya tidak portabel ke jenis komputer lain. Dalam 25 tahun terakhir saya telah menulis sekitar 8 baris assembler, dan itu menghasilkan kondisi kesalahan untuk menguji penangan kesalahan.

1 postasaguest Jan 22 2021 at 23:25

Tidak saat saya bekerja dengan komputer saat itu. Kami mengalami banyak masalah tetapi saya tidak pernah mengalami masalah kerusakan memori.

Sekarang saya bekerja pada beberapa mesin IBM 7090,360,370, s / 3, s / 7 dan juga mikro berbasis 8080 dan Z80. Komputer lain mungkin memiliki masalah memori.