Bahasa pemrograman aman (PL) semakin populer. Saya ingin tahu apa definisi formal PL yang aman. Misalnya, C tidak aman, tetapi Java aman. Saya menduga bahwa properti "aman" harus diterapkan untuk implementasi PL daripada PL itu sendiri. Jika demikian, mari kita bahas definisi implementasi PL yang aman. Upaya saya sendiri untuk memformalkan gagasan ini menghasilkan hasil yang aneh, jadi saya ingin mendengar pendapat lain. Tolong, jangan katakan bahwa setiap PL memiliki perintah yang tidak aman. Kami selalu dapat mengambil bagian yang aman.
programming-languages
beroal
sumber
sumber
Jawaban:
Ketika kita menyebut bahasa "aman" dalam beberapa hal , itu secara resmi berarti bahwa ada bukti bahwa tidak ada program yang baik dalam bahasa yang dapat melakukan sesuatu yang kita anggap berbahaya. Kata "aman" juga digunakan secara kurang formal, tapi itulah yang orang di sini pahami maksud pertanyaan Anda. Ada banyak definisi properti yang berbeda yang kami inginkan memiliki bahasa "aman".
Beberapa yang penting adalah:
Definisi Andrew Wright dan Matthias Felleisen tentang "kesehatan jenis" , yang dikutip di banyak tempat (termasuk Wikipedia) sebagai definisi yang diterima tentang "keamanan jenis," dan bukti 1994 mereka bahwa subset dari ML memenuhi itu.
Michael Hicks mendaftar beberapa definisi "keamanan memori" di sini . Beberapa adalah daftar jenis kesalahan yang tidak dapat terjadi, dan beberapa didasarkan pada memperlakukan pointer sebagai kemampuan. Java menjamin bahwa tidak ada kesalahan tersebut yang dimungkinkan (kecuali jika Anda secara eksplisit menggunakan fitur bertanda
unsafe
) dengan meminta seorang pengumpul sampah mengelola semua alokasi dan deallokasi. Rust membuat jaminan yang sama (sekali lagi, kecuali jika Anda secara eksplisit menandai kode sebagaiunsafe
), melalui sistem tipe affine-nya, yang membutuhkan variabel untuk dimiliki atau dipinjam sebelum digunakan paling banyak sekali.Demikian pula, kode aman thread biasanya didefinisikan sebagai kode yang tidak dapat menunjukkan jenis bug tertentu yang melibatkan utas dan memori bersama, termasuk ras data dan kebuntuan. Properti ini sering diberlakukan pada tingkat bahasa: Rust menjamin bahwa balapan data tidak dapat terjadi dalam sistem tipenya, C ++ menjamin bahwa
std::shared_ptr
smart pointernya ke objek yang sama di banyak utas tidak akan menghapus objek sebelum waktunya atau gagal menghapusnya ketika referensi terakhir untuk itu dihancurkan, C dan C ++ juga memilikiatomic
variabel dibangun ke dalam bahasa, dengan operasi atom dijamin untuk menegakkan beberapa jenis memori-konsistensi jika digunakan dengan benar. MPI membatasi komunikasi antarproses ke pesan eksplisit, dan OpenMP memiliki sintaks untuk memastikan bahwa akses ke variabel dari utas yang berbeda aman.Properti yang memori tidak akan pernah bocor sering disebut safe-for-space. Pengumpulan sampah otomatis adalah fitur satu bahasa untuk memastikan hal ini.
Banyak bahasa memiliki jaminan bahwa operasinya akan memiliki hasil yang jelas dan program-programnya akan berperilaku baik. Sebagai supercat memberikan contoh di atas, C melakukan ini untuk aritmatika yang tidak ditandatangani (dijamin untuk membungkus dengan aman) tetapi tidak menandatangani aritmatika (di mana overflow diizinkan untuk menyebabkan bug yang sewenang-wenang, karena C perlu mendukung CPU yang melakukan hal-hal yang sangat berbeda ketika menandatangani aritmatika meluap), tetapi kemudian bahasa terkadang secara diam-diam mengubah jumlah yang tidak ditandatangani menjadi yang ditandatangani.
Bahasa fungsional memiliki banyak invarian yang dijamin dapat dipertahankan oleh setiap program yang dibentuk dengan baik, misalnya, fungsi murni tidak dapat menyebabkan efek samping. Ini mungkin atau mungkin tidak digambarkan sebagai "aman."
Beberapa bahasa, seperti SPARK atau OCaml, dirancang untuk memfasilitasi pembuktian kebenaran program. Ini mungkin atau mungkin tidak digambarkan sebagai "aman" dari bug.
Bukti bahwa suatu sistem tidak dapat melanggar model keamanan formal (oleh karena itu menyindir, "Setiap sistem yang terbukti aman mungkin tidak.")
sumber
Tidak ada definisi formal "bahasa pemrograman yang aman"; itu gagasan informal. Sebaliknya, bahasa yang mengklaim memberikan keamanan biasanya memberikan pernyataan formal yang tepat tentang jenis keamanan apa yang diklaim / dijamin / disediakan. Misalnya, bahasa dapat memberikan keamanan jenis, keamanan memori, atau jaminan serupa lainnya.
sumber
double
ataulong
sementara itu sedang diubah di utas lain, yang tidak dijamin tidak menghasilkan setengah dari satu nilai yang dicampur dalam cara yang tidak ditentukan dengan setengah lainnya) tetapi spesifikasi API Namun memiliki perilaku yang tidak terdefinisi dalam beberapa kasus.Jika Anda bisa mendapatkan salinan Jenis dan Bahasa Pemrograman Benjamin Pierce , dalam pengantar, ia memiliki tinjauan yang baik tentang berbagai perspektif tentang istilah "bahasa aman".
Salah satu interpretasi yang diusulkan dari istilah yang mungkin Anda temukan menarik adalah:
Jadi, saya akan ragu untuk menggunakan istilah "tidak aman" untuk merujuk pada implementasi bahasa pemrograman. Jika istilah yang tidak didefinisikan dalam bahasa menghasilkan perilaku yang berbeda dalam implementasi yang berbeda, salah satu implementasi mungkin perilaku produk yang mungkin lebih diharapkan, tetapi saya tidak akan menyebutnya "aman".
sumber
Aman bukan biner, ini sebuah rangkaian .
Berbicara secara informal, keselamatan dimaksudkan oleh oposisi terhadap bug, 2 yang paling sering disebutkan adalah:
Itu bukan satu - satunya kelas bug yang mencegah bahasa, kebebasan data-ras atau kebuntuan agak diinginkan, bukti kebenaran cukup manis, dll ...
Cukup program yang salah jarang dianggap "tidak aman" namun (hanya kereta), dan keamanan jangka umumnya dicadangkan untuk jaminan mempengaruhi kemampuan kita untuk alasan tentang program. Dengan demikian, C, C ++ atau Go, yang memiliki Perilaku Tidak Terdefinisi, tidak aman.
Dan tentu saja, ada bahasa dengan himpunan bagian yang tidak aman (Java, Rust, ...) yang dengan sengaja menggambarkan area di mana pengembang bertanggung jawab untuk menjaga jaminan bahasa dan kompiler berada dalam mode "lepas tangan". Bahasa-bahasa tersebut pada umumnya masih dijuluki aman , terlepas dari jalan keluarnya ini, sebuah definisi pragmatis.
sumber
Obj.magic
dalam Ocaml). Dan dalam praktiknya, ini sangat diperlukanMeskipun saya tidak setuju dengan jawaban DW, saya pikir itu membuat satu bagian dari "aman" tidak tertangani.
Seperti disebutkan, ada beberapa jenis keselamatan yang dipromosikan. Saya percaya itu baik untuk memahami mengapa ada banyak konsep. Setiap gagasan dikaitkan dengan gagasan bahwa program menderita terutama dari kelas bug tertentu, dan bahwa programmer tidak akan dapat membuat bug jenis khusus ini jika bahasa tersebut menghalangi programmer untuk melakukannya.
Perlu dicatat bahwa konsep-konsep yang berbeda ini karena itu memiliki kelas bug yang berbeda, dan kelas-kelas ini tidak saling eksklusif dan kelas-kelas ini tidak mencakup semua bentuk bug. Hanya untuk mengambil 2 contoh DW, pertanyaan apakah lokasi memori tertentu memegang objek tertentu adalah pertanyaan tentang keamanan jenis dan keamanan memori.
Kritik lebih lanjut terhadap "bahasa yang aman" mengikuti dari pengamatan bahwa pelarangan konstruksi tertentu yang dianggap berbahaya membuat programmer perlu membuat alternatif. Secara empiris, keamanan lebih baik dicapai oleh perpustakaan yang baik. menggunakan kode yang sudah teruji lapangan menyelamatkan Anda dari membuat bug baru.
sumber
Perbedaan mendasar antara C dan Java adalah bahwa jika seseorang menghindari fitur Java yang mudah diidentifikasi (misalnya yang ada di
Unsafe
namespace), setiap tindakan yang mungkin dilakukan - termasuk yang "keliru" - akan memiliki sejumlah hasil yang terbatas. . Walaupun hal ini membatasi apa yang dapat dilakukan seseorang di Jawa - setidaknya tanpa menggunakanUnsafe
namespace, itu juga memungkinkan untuk membatasi kerusakan yang dapat disebabkan oleh program yang salah, atau - yang lebih penting - oleh program yang akan memproses dengan benar file yang valid tetapi tidak secara khusus dilindungi terhadap yang salah.Secara tradisional, kompiler C akan memproses banyak tindakan dengan cara yang ditentukan standar dalam kasus "normal", sementara memproses banyak kasus sudut "dengan cara yang karakteristik lingkungan". Jika seseorang menggunakan CPU yang akan memendek dan terbakar jika numerik meluap dan ingin menghindari CPU yang terbakar, orang perlu menulis kode untuk menghindari kelebihan numerik. Namun, jika seseorang menggunakan CPU yang dengan sempurna akan memotong nilai dengan cara dua-pelengkap, seseorang tidak harus menghindari kelebihan dalam kasus di mana pemotongan tersebut akan menghasilkan perilaku yang dapat diterima.
Modern C mengambil langkah-langkah lebih jauh: bahkan jika seseorang menargetkan platform yang secara alami akan mendefinisikan perilaku untuk sesuatu seperti pelimpahan numerik di mana Standar tidak akan memaksakan persyaratan, melimpah di satu bagian dari program dapat memengaruhi perilaku bagian lain dari Program dengan cara sewenang-wenang yang tidak terikat oleh hukum waktu dan kausalitas. Sebagai contoh, pertimbangkan sesuatu seperti:
Kompiler C "modern" yang diberi sesuatu seperti di atas mungkin menyimpulkan bahwa karena perhitungan x * x akan meluap jika x lebih besar dari 46340, ia dapat melakukan panggilan ke "foo" tanpa syarat. Perhatikan bahwa meskipun akan dapat diterima jika sebuah program berhenti secara tidak normal jika x berada di luar jangkauan, atau meminta fungsi mengembalikan nilai apa pun dalam kasus seperti itu, memanggil foo () dengan out-of-range x dapat menyebabkan kerusakan jauh melampaui salah satu dari kemungkinan itu. Tradisional C tidak akan menyediakan alat pengaman apa pun di luar apa yang disediakan oleh programmer dan platform yang mendasarinya, tetapi akan memungkinkan alat pengaman membatasi kerusakan dari situasi yang tidak terduga. Modern C akan mem-bypass setiap peralatan keselamatan yang tidak 100% efektif untuk menjaga semuanya terkendali.
sumber
int
32 bit, makax
akan dipromosikan untuk ditandatanganiint
. Dilihat dari alasannya, penulis Standar berharap bahwa implementasi non-aneh akan memperlakukan jenis yang ditandatangani dan tidak ditandatangani dengan cara yang setara di luar beberapa kasus tertentu, tetapi gcc kadang-kadang "mengoptimalkan" dengan cara yang memecah jika auint16_t
denganuint16_t
berlipat ganda menghasilkan hasil di luar INT_MAX , bahkan ketika hasilnya digunakan sebagai nilai yang tidak ditandatangani.-Wconversion
.return x+1;
yang seharusnya tidak menjadi masalah, dan memberikan hasilnya ke uint32_t akan melumpuhkan pesan tanpa memperbaiki masalah.Ada beberapa lapisan kebenaran dalam suatu bahasa. Dalam rangka meningkatkan abstraksi:
Pada level berikutnya, kesalahan yang terdeteksi pada waktu kompilasi alih-alih pada saat run time membuat bahasa lebih aman. Program yang benar secara sintaksis juga semestinya benar semaksimal mungkin. Tentu saja kompiler tidak dapat mengetahui gambaran besarnya, jadi ini menyangkut level detail. Tipe data yang kuat dan ekspresif adalah salah satu aspek keselamatan pada level ini. Orang bisa mengatakan bahasanya harus menyulitkan untuk membuat kesalahan jenis tertentu(ketik kesalahan, akses tidak terbatas, variabel tidak diinisialisasi, dll.). Informasi jenis run-time seperti array yang membawa informasi panjang menghindari kesalahan. Saya memprogram Ada 83 di perguruan tinggi dan menemukan bahwa program kompilasi Ada biasanya berisi urutan kesalahan yang lebih kecil daripada program C yang sesuai. Ambil saja kemampuan Ada untuk menentukan tipe bilangan bulat yang tidak dapat ditentukan pengguna tanpa konversi eksplisit: Seluruh kapal ruang angkasa jatuh karena kaki dan meter bingung, yang bisa dihindari orang dengan Sepele.
Pada level selanjutnya, bahasa harus menyediakan cara untuk menghindari kode boilerplate. Jika Anda harus menulis wadah sendiri, atau penyortirannya, atau gabungannya, atau jika Anda harus menulis sendiri,
string::trim()
Anda akan membuat kesalahan. Karena tingkat abstraksi naik kriteria ini melibatkan bahasa yang tepat serta perpustakaan standar bahasa.Hari-hari ini bahasa harus menyediakan sarana untuk pemrograman bersamaan pada tingkat bahasa. Konkurensi sulit untuk diperbaiki dan mungkin mustahil dilakukan dengan benar tanpa dukungan bahasa.
Bahasa harus menyediakan sarana untuk modularisasi dan kolaborasi. Jenis yang kuat, rumit, yang ditentukan pengguna dari atas membantu membuat API ekspresif.
Agak orthogonal definisi bahasa harus dapat dipahami; bahasa dan perpustakaan harus didokumentasikan dengan baik. Dokumentasi yang salah atau hilang menyebabkan program yang salah dan salah.
1 Tetapi karena biasanya kebenaran dari mesin virtual tidak dapat dibuktikan bahasa-bahasa semacam itu mungkin agak tidak cocok untuk persyaratan keamanan yang sangat ketat.
sumber
Setiap bahasa yang saya tahu memiliki cara menulis program ilegal yang dapat (dikompilasi dan) dijalankan. Dan setiap bahasa yang saya tahu memiliki bagian yang aman. Jadi, apa pertanyaanmu sebenarnya?
Keamanan multidimensi dan subyektif.
Beberapa bahasa memiliki banyak operasi yang "tidak aman". Lainnya memiliki operasi yang lebih sedikit. Dalam beberapa bahasa, cara standar melakukan sesuatu pada dasarnya tidak aman. Pada yang lain, cara defaultnya aman. Dalam beberapa bahasa, ada subset eksplisit "tidak aman". Dalam bahasa lain, tidak ada himpunan bagian sama sekali.
Dalam beberapa bahasa, "keselamatan" mengacu secara eksklusif pada keamanan memori - layanan yang ditawarkan oleh perpustakaan standar dan / atau runtime di mana pelanggaran akses memori menjadi sulit atau tidak mungkin. Dalam bahasa lain, "safety" secara eksplisit menyertakan safety thread. Dalam bahasa lain, "keselamatan" mengacu pada jaminan bahwa suatu program tidak akan macet (persyaratan yang mencakup tidak mengizinkan pengecualian apa pun yang tidak tertangkap). Akhirnya, dalam banyak bahasa "keselamatan" mengacu pada keselamatan tipe - jika sistem tipe konsisten dalam cara-cara tertentu, dikatakan sebagai "suara" (kebetulan, Java dan C # tidak memiliki sistem tipe suara sepenuhnya).
Dan dalam beberapa bahasa, semua arti "keselamatan" yang berbeda dianggap sebagai himpunan bagian dari jenis keamanan (mis. Rust dan Pony mencapai keamanan benang melalui sifat-sifat sistem jenis).
sumber
Jawaban ini sedikit lebih luas. Kata-kata aman dan keselamatan dalam beberapa dekade terakhir telah dimutilasi oleh bagian-bagian tertentu dari masyarakat berbahasa Inggris yang berorientasi politik, sehingga penggunaan umum mereka hampir tidak memiliki definisi. Namun, untuk subjek teknis saya masih kembali untuk mendefinisikan "keselamatan" dan "aman" sebagai: perangkat yang mencegah penggunaan sesuatu yang tidak disengaja atau yang membuat penggunaan tidak disengaja secara substansial lebih sulit, dan keadaan di bawah perlindungan perangkat seperti itu .
Jadi bahasa yang aman memiliki beberapa perangkat untuk membatasi kelas bug tertentu. Tentu saja batasan datang dengan ketidaknyamanan atau bahkan ketidakmampuan dalam beberapa kasus, dan itu tidak berarti bahwa bahasa "tidak aman" akan menghasilkan bug. misalnya saya tidak memiliki sumbat pengaman di garpu dan selama beberapa dekade berhasil, tanpa banyak usaha, untuk menghindari menusuk mata saya saat makan. Tentu saja lebih sedikit upaya daripada yang akan dikeluarkan menggunakan gabus. Jadi Keselamatan dilengkapi dengan biaya yang harus dinilai. (Garpu gabus adalah referensi ke karakter Steve Martin)
sumber