Bagaimana kita bisa yakin bahwa komponen yang lebih rendah dari pemrograman komputer seperti kompiler, assembler, instruksi mesin, dll. Sempurna?

57

Karena kita menjadi semakin bergantung pada komputasi, termasuk tugas-tugas yang sangat penting dalam kehidupan sehari-hari, saya hanya ingin tahu bagaimana komponen-komponen vital tersebut diuji.

Lebih teknis, bagaimana kompiler dan perakit diuji? (Saya kira ini berkaitan dengan masalah penghentian !!)

Sudip Bhandari
sumber
36
Anda mungkin ingin memulai penelitian Anda dengan "Ken Thompson Hack" Lihat Refleksi tentang Kepercayaan yang Dipercaya
Bryan Oakley
7
Berikut ini adalah contoh dari kompiler yang ada bukti kebenarannya: compcert.inria.fr/doc/index.html
Giorgio
8
Sebagian besar penyusun / penghubung / perakit diuji paling dalam dengan menggunakannya dalam banyak keadaan yang berbeda. Untuk menemukan kesalahan, tidak ada yang di atas memiliki jutaan pengguna menggunakan kompiler Anda.
Bart van Ingen Schenau
3
dan menambahkan Sistem Operasi ke daftar, juga.
Erik Eidt

Jawaban:

104

Anda tidak dapat memastikan, tetapi Anda hanya berasumsi bahwa itu benar, sampai Anda tahu tidak. Ada banyak bug dalam kompiler dan perangkat keras selama bertahun-tahun.

Cara ini diuji, misalnya kompiler, adalah bahwa mereka sangat sempit dan kaku, ditulis dengan hati-hati, kemudian diuji dengan suite uji yang sangat besar untuk memverifikasi kebenaran. Tambahkan ke basis pengguna yang luas dari kompiler, dan lebih banyak bug akan terdeteksi dan dilaporkan. Aplikasi penjadwalan janji temu dokter gigi, secara relatif, memiliki lebih sedikit pengguna, dan lebih sedikit lagi yang mampu mendeteksi cacat.

SQLite terdiri dari sekitar 73k baris kode, sedangkan test suite-nya terdiri dari sekitar 91378k baris kode, lebih dari 1250 kali lipat dari SQLite itu sendiri. Saya berharap kompiler dan alat inti lainnya memiliki rasio yang sama. Prosesor saat ini pada dasarnya dirancang dengan perangkat lunak, menggunakan bahasa deskripsi perangkat keras seperti Verilog atau VHDL, dan yang memiliki tes perangkat lunak juga berjalan di atasnya, serta pin IO khusus untuk menjalankan tes mandiri pada titik pembuatan.

Pada akhirnya, ini adalah permainan probabilitas, dan pengujian yang diulang dan luas memungkinkan Anda untuk mendorong probabilitas cacat ke tingkat yang dapat diterima rendah, sama seperti proyek perangkat lunak lain.

Apa namanya
sumber
7
Saya sering bertanya-tanya pertanyaan yang sama dengan OP, tetapi sehubungan dengan DBMS. Anda memberikan contoh yang bagus yang menjawabnya dalam konteks SQLite. Terima kasih!
Brandon
7
+1 tetapi entah bagaimana saya ragu bahwa "kompiler dan alat inti lainnya memiliki rasio yang sama".
Mehrdad
5
Perhatikan bahwa (1) SQLite sebenarnya memiliki dua test suite, dengan redundansi non-sepele antara keduanya dan (2) masih ada bug yang ditemukan di SQLite meskipun demikian.
Matthieu M.
7
Saya mendapat kesan bahwa SQLite adalah salah satu perangkat lunak yang paling "diuji secara ekstensif" (dalam hal garis kode pengujian / baris kode operasional) yang tersedia untuk penggunaan umum, bahkan lebih daripada banyak kompiler. Jika tidak ada yang lain, kompiler berfitur lengkap adalah perangkat lunak yang sangat besar, dan saya tidak dapat membayangkannya memiliki seribu kali jumlah kode pengujian. (GCC dilaporkan mencapai 14,5 juta baris. Tampaknya tidak mungkin bahwa kumpulan pengumpulan yang tepat hanya 14k LOC, atau bahwa mereka memiliki basis kode uji 14-miliar-baris yang duduk di samping! :-P)
David Z
2
@ DavidZ: Ya, tentu saja itu satu-satunya proyek yang saya tahu menggunakan pengujian OOM yang luas misalnya (mereka menggunakan injektor kesalahan untuk pengujian dan mengulanginya lagi dan lagi gagal pada tanggal 1, kemudian alokasi 2 ... sampai seluruh pengujian dieksekusi).
Matthieu M.
46

Dalam istilah awam:

  1. Kamu tidak bisa.
  2. Compiler dan interpreter diuji unit seperti perangkat lunak (profesional) lainnya.
  3. Tes yang berhasil tidak berarti suatu program bebas bug, itu hanya berarti tidak ada bug yang terdeteksi.
  4. Basis pengguna yang luas menggunakan kompiler dalam waktu yang lama adalah indikator yang cukup bahwa ia memiliki sedikit bug, karena pengguna biasanya menguji kasus yang tidak dipikirkan oleh perancang.
  5. Menjadi open source juga merupakan indikator yang baik. "Diberi cukup banyak bola mata, semua bug dangkal ... Diberi beta-tester dan co-developer base yang cukup besar, hampir setiap masalah akan ditandai dengan cepat dan perbaikannya akan jelas bagi seseorang." . Kompiler sumber tertutup dapat memiliki bug yang muncul pada waktu yang sangat spesifik atau yang menghasilkan kode mesin kurang optimal dan perusahaan di belakangnya tidak bisa mengungkapkan keberadaan mereka dan memberikannya prioritas yang sangat rendah dalam peta jalan produk.

Intinya:

Saya akan mengatakan pergi untuk OOP ( O ld, O pena dan P opular). Saya baru saja mengarang akronim itu.

Tulains Córdova
sumber
19
+1 Untuk menemukan TLA lain (singkatan tiga huruf) - dunia belum cukup memilikinya.
s1lv3r
34
Juga, OOP belum memiliki arti dalam pemrograman komputer. Jadi KTT (pujian untukmu)!
Pierre Arlaud
15
Komentar Pierre adalah lelucon @Dannnno.
yannis
19
Atau, itu bisa P opular, O ld, dan O pen. ;) Sebenarnya, itulah cara saya memberi peringkat pada mereka menurut kepentingan.
jpmc26
23
@ jpmc26 Saya akan menggunakan Praktis, Tua, Terbuka, dan Populer. Adapun akronim ...
StupidOne
24

Ini kura-kura sepanjang jalan.

Tidak ada yang pasti. Anda tidak punya pilihan selain menentukan peringkat kepercayaan diri.

Anda dapat menganggapnya sebagai tumpukan: Matematika> Fisika> Perangkat Keras> Firmware> Sistem Operasi> Assembler / Kompiler / dll

Di setiap level Anda memiliki tes yang dapat Anda lakukan untuk meningkatkan peringkat kepercayaan diri Anda. Beberapa dari tes ini memiliki kualitas bukti formal, beberapa di antaranya didasarkan pada pengamatan, sebagian besar merupakan kombinasi dari keduanya.

Bagian yang sulit adalah mengurai rekursi dalam beberapa tes ini karena kami menggunakan program untuk melakukan pembuktian dan analisis pengamatan sekarang di mana telah menjadi terlalu sulit untuk melakukannya dengan tangan.

Meskipun akhirnya jawabannya adalah bahwa Anda mencoba semua yang dapat Anda pikirkan. Analisis statis, fuzzing, simulasi, berjalan dengan input ekstrim yang dipilih dengan sengaja atau input acak, menjalankan / memetakan setiap jalur kontrol, bukti formal, dll. Pada dasarnya tujuan Anda dalam pengujian harus selalu melakukan segala kemungkinan untuk membuktikan bahwa produk Anda (misalnya teori / chip / program) tidak berfungsi sebagaimana dimaksud. Jika Anda melakukan upaya yang tulus dan masih gagal maka Anda diizinkan untuk meningkatkan peringkat kepercayaan Anda pada kebenaran produk Anda.

Pengujian adalah proses semi-keputusan yang berarti bahwa mengingat ada bug Anda akhirnya akan menemukannya tetapi Anda tidak pernah yakin bahwa Anda telah menemukan semuanya. Bahkan dengan perangkat lunak yang diverifikasi secara formal Anda masih mengandalkan fisika, alat yang digunakan untuk melakukan bukti formal, dan bahwa hal yang Anda buktikan perlu dan cukup bagi program Anda untuk melakukan apa yang (sering secara subyektif) "dimaksudkan". Belum lagi semua komponen lain yang Anda gunakan yang tidak memiliki bukti formal.

voutasaurus
sumber
17

Ini adalah pertanyaan "berbahaya" untuk pengembang baru karena mereka akan mulai menyalahkan alat mereka alih-alih kode mereka (sudah ada, melakukannya, terlihat terlalu banyak melakukannya). Meskipun ada bug di kompiler, lingkungan runtime, OS, dll. Pengembang harus realistis dan ingat bahwa, sampai ada bukti dan unit test menunjukkan sebaliknya, bug ada di kode Anda .

Dalam 25+ tahun pemrograman di sebagian besar C, C ++, dan Java saya telah menemukan:

  • dua bug karena bug kompilator (gcc dan SunOS C)
  • sekitar sekali atau dua tahun sekali bug karena masalah Java JVM (biasanya terkait dengan konsumsi memori / pengumpulan sampah)
  • sekitar sebulan sekali atau dua bug di perpustakaan, yang sering diperbaiki dengan menggunakan versi terbaru atau kembali ke versi sebelumnya dari perpustakaan

Semua bug lain secara langsung terkait dengan bug atau, lebih sering, kurangnya pemahaman tentang cara kerja perpustakaan. Kadang-kadang apa yang tampaknya menjadi bug adalah karena ketidakcocokan, misalnya bagaimana struktur kelas Java berubah yang merusak beberapa pustaka AOP.

Ed Griebel
sumber
Saya ingin tahu - tahun mana untuk bahasa yang mana? Kembali di EGCS hari sebelum C ++ distandarisasi dengan benar, bug kompiler tidak begitu sulit ditemukan ...
Charles Duffy
3
Semakin tidak jelas compiler, cpu atau bahasa semakin mudah sehingga menemukan bug di kompiler (sebelum orang lain) sehingga menemukan 2 di GCC C bagus :)
Surt
1
Ketika itu terjadi, saya hanya menyia-nyiakan sekitar satu bulan dengan anggapan bahwa masalah yang saya alami ada di skrip gdb saya, atau pemahaman saya tentang apa yang saya periksa. Akhirnya saya merasa curiga, menyederhanakan kasus pengujian saya, dan menemukan cacat desain di perpustakaan (libkvm), yang membuat debugger kernel tidak dapat mengakses alamat tertentu dari dump inti. Yaitu YMMV - dan saya paling bahagia ketika saya menemukan bug baru di kode hulu saya, terutama sesuatu yang saya gunakan daripada mengembangkan.
Arlie Stephens
Tentu saja itu bukan bug penyusun , atau bahkan salah satu perpustakaan yang lebih umum digunakan. Dan sejujurnya, saya tidak menemukan bug pada mereka dengan frekuensi sama sekali.
Arlie Stephens
@ArlieStephens Ada pelajaran di sana: menyederhanakan test case Anda adalah sesuatu yang harus Anda lakukan sejak awal ketika Anda gagal menemukan masalah. Terlepas dari apakah masalahnya ada pada Anda atau kode lain, itu akan membantu Anda mempersempitnya. Seringkali, jika masalahnya ada pada kode lain, ini akan menghasilkan, "bukti dan tes unit menunjukkan" begitu.
jpmc26
8

Saya pikir poin yang menarik di sini adalah bahwa sebagian besar lisensi perangkat lunak komersial (dan bahkan perangkat lunak open source) secara spesifik menentukan bahwa Anda tidak dapat mempercayai perangkat lunak tersebut.

PERANGKAT LUNAK INI DISEDIAKAN "SEBAGAIMANA ADANYA", TANPA JAMINAN APA PUN, BAIK TERSURAT MAUPUN TERSIRAT, TERMASUK TETAPI TIDAK TERBATAS PADA JAMINAN PENJUALAN DAGANG, KESESUAIAN UNTUK TUJUAN TERTENTU DAN TUJUAN NON.

Dari perjanjian Lisensi Microsoft Word

. Kecuali untuk Jaminan Terbatas dan sejauh yang diizinkan oleh undang-undang yang berlaku, Microsoft dan pemasoknya menyediakan Perangkat Lunak dan layanan dukungan (jika ada) SEBAGAIMANA ADANYA DAN DENGAN SEMUA KEREN, dan dengan ini menafikan semua jaminan dan ketentuan lainnya, baik tersurat, tersirat maupun menurut undang-undang, termasuk, tetapi tidak terbatas pada, setiap (jika ada) jaminan tersirat, tugas atau ketentuan yang dapat diperjualbelikan, kesesuaian untuk tujuan tertentu, keandalan atau ketersediaan, keakuratan atau kelengkapan tanggapan, hasil, dari usaha yang keras, dari kurangnya virus, dan kurangnya kelalaian, semua yang berkaitan dengan Perangkat Lunak, dan penyediaan atau kegagalan untuk memberikan dukungan atau layanan, informasi, perangkat lunak, dan konten terkait lainnya melalui Perangkat Lunak atau yang timbul dari penggunaan Perangkat Lunak .

Pada intinya kalimat ini dalam lisensi di hampir setiap bagian dari perangkat lunak yang Anda gunakan secara khusus memberi tahu Anda bahwa Anda tidak dapat mempercayai perangkat lunak apalagi kompiler yang digunakan.

Perangkat lunak seperti teori ilmiah, dianggap berfungsi sebagaimana ditentukan hingga tidak.

Toby Allen
sumber
+1 untuk menunjukkan bahwa lisensi tersebut menyatakan bahwa tidak ada perangkat lunak yang sempurna.
Tulains Córdova
3
Saya merasa bersyukur mencatat penyimpangan dari praktik ini dalam ViaVoice untuk Mac IBM. Alih-alih kebiasaan "jika tidak bekerja, terlalu buruk" mereka benar-benar mengatakan sesuatu seperti "Perangkat lunak ini dijamin untuk melakukan seperti yang ditentukan."
WGroleau
1
Terjemahan sederhana dari kalimat jaminan ini adalah, "Ini mungkin perangkat lunak, atau mungkin sepotong sh * t. Mungkin berhasil. Mungkin tidak. Bahkan jika itu berfungsi, mungkin tidak lakukan apa yang kau mau Oh-ngomong-ngomong, kita mungkin telah mencuri sedikit dari orang lain. Sayang sekali. Kita punya uangmu dan menggunakannya untuk menyewa banyak pengacara. GAME! AKTIF! Nyah-nyah -nyah-nyah-nyaaah-naah! ". :-)
Bob Jarvis
2
@ BobJarvis: Pernyataan jaminan favorit saya, yang digunakan pada beberapa perangkat lunak sumber terbuka (seperti nmap IIRC), adalah "Jika rusak, Anda harus menyimpan kedua bagian".
Peter Cordes
Pernyataan ini ada di mana-mana dalam perangkat lunak sumber terbuka, dan banyak perangkat lunak sumber bebas tertutup. Itu tidak muncul di sebagian besar lisensi perangkat lunak berbayar komersial.
jwg
2

Sebagai penulis kompiler untuk bahasa matematika *, dari pengalaman saya, saya bisa mengatakan secara teori Anda tidak bisa. Dan beberapa bug hanya memberikan hasil yang salah seperti (dari daftar malu saya) menghitung 6/3*2dari kanan 6/(3*2)dan menghasilkan 1 tanpa menabrak atau memberikan kesalahan kompilasi tidak masuk akal.

Tetapi banyak kompiler IMHO tidak memiliki bug sebanyak perangkat lunak lain karena:

  • Tes unit menulis itu mudah. Setiap pernyataan adalah unit dan Anda dapat menulis tes sesederhana:test_unit("2+(-2)*(-2+1)*3+1",9);
  • Suatu program adalah kombinasi dari pernyataan dan untuk program apa pun untuk menghasilkan hasil yang benar, setiap pernyataan individu harus memberikan hasil yang benar (kebanyakan). Jadi sangat tidak mungkin memiliki bug saat program memberikan hasil yang benar.
  • Karena ukuran dan jumlah program tertulis meningkatkan kemungkinan menangkap bug meningkat secara dramatis.

Untuk perakit, instruksi mesin dll, di atas juga tahan; di sisi lain verifikasi dan validasi dalam desain dan produksi chip memiliki banyak proses yang lebih ketat karena ini adalah bisnis besar: otomatisasi desain elektronik .

Sebelum mulai berproduksi, setiap CPU harus diuji secara ketat karena setiap bug menelan biaya hampir beberapa juta dolar: ada biaya produksi besar yang tidak berulang dalam produksi chip. Jadi perusahaan menghabiskan banyak uang dan menulis banyak kode simulasi untuk desain mereka sebelum produksi, meskipun ini tidak memberikan jaminan 100% - misalnya: bug Pentium FDIV.

Singkatnya, sangat tidak mungkin ada bug serius dalam kompiler, kode mesin, dll.

Bahasa matematika saya yang sederhana *

Gorkem
sumber
Intel menguji dari CPU mereka dengan menjalankan urutan instruksi acak dan membandingkan dengan model perangkat lunak, antara lain: tweakers.net/reviews/740/4/… . Inilah sebabnya mengapa Anda sering melihat errata yang sangat tidak jelas dipublikasikan, untuk beberapa kombinasi instruksi yang benar-benar tidak mungkin dalam mode yang tidak biasa.
Peter Cordes
0

Sempurna? Mereka tidak. Saya baru-baru ini menginstal beberapa "pembaruan", dan itu berbulan-bulan (dan beberapa bagian kode diprogram ulang) kemudian sebelum situs ASP.NET saya berfungsi dengan baik lagi, karena perubahan yang tidak dapat dijelaskan tentang bagaimana berbagai hal dasar bekerja atau gagal.

Namun, mereka diuji dan kemudian digunakan oleh banyak orang berorientasi detail yang sangat cerdas, yang cenderung memperhatikan dan melaporkan dan memperbaiki sebagian besar hal. Stack Exchange adalah contoh yang bagus (dan peningkatan pada) bagaimana semua orang yang menggunakan alat-alat itu membantu menguji dan menganalisis bagaimana alat-alat tingkat luar biasa kompleks dan rendah ini bekerja, setidaknya sejauh penggunaan praktis berjalan.

Tapi tanpa cacat, tidak. Meskipun Anda juga dapat melihat orang-orang di Stack Exchange mendapatkan wawasan yang mengesankan tentang detail kinerja dan standar kepatuhan serta keanehan, selalu ada kekurangan dan ketidaksempurnaan, terutama ketika orang yang berbeda memiliki pendapat berbeda tentang apa itu cacat.

Dronz
sumber
-1

Untuk menunjukkan bahwa sistem yang mendasarinya juga sempurna bagi Anda

a) Perlu membuktikan bahwa mereka sempurna

  1. Bukti matematis
  2. Hanya mungkin secara realistis untuk program sepele

b) Lakukan tes yang lengkap

  1. Hanya mungkin untuk program sepele dan beberapa program sederhana
  2. Segera setelah elemen waktu memasuki tes, tidak mungkin untuk melakukan tes lengkap karena waktu dapat dibagi tanpa batas waktu.
  3. Di luar program-program sepele, opsi eksekusi yang mungkin meledak secara eksponensial.

Dalam pengujian perangkat lunak, pengujian lengkap hanya digunakan dalam pengujian unit terhadap beberapa fungsi sederhana.

Contoh: Anda ingin menguji input 8 karakter utf-8 ke beberapa bidang, Anda membuat pilihan untuk memotong input pada 8 kali panjang maksimum 6 dari utf-8 dalam byte yang memberikan 8 * 6 = 48 byte untuk benar-benar memiliki jumlah kemungkinan yang terbatas.

Anda sekarang bisa berpikir Anda hanya perlu menguji 1.112.064 poin kode yang valid dari masing-masing 8 karakter, yaitu. 1.112.064 ^ 8 (katakanlah 10 ^ 48) tes (yang sudah tidak mungkin mungkin), tetapi Anda benar-benar harus menguji setiap nilai masing-masing dari 48 byte atau 256 ^ 48 yaitu sekitar 10 ^ 120 yang kompleksitasnya sama dengan catur dibandingkan dengan jumlah total atom di alam semesta sekitar 10 ^ 80.

Sebagai gantinya Anda dapat menggunakannya, dengan meningkatkan urutan upaya dan setiap tes harus mencakup semua yang sebelumnya:

a) menguji sampel yang baik dan yang buruk.

b) cakupan kode, yaitu. cobalah untuk menguji setiap baris kode, yang relatif sederhana untuk sebagian besar kode. Sekarang Anda dapat bertanya-tanya apa 1% terakhir dari kode yang tidak dapat Anda uji ada ... bug, kode mati, pengecualian perangkat keras dll.

c) cakupan jalur, semua hasil dari semua cabang di semua kombinasi diuji. Sekarang Anda tahu mengapa departemen pengujian membenci Anda ketika fungsi Anda berisi lebih dari 10 kondisi. Anda juga bertanya-tanya mengapa 1% terakhir tidak dapat diuji ... beberapa cabang tergantung pada cabang sebelumnya.

d) uji data, uji sejumlah sampel dengan nilai batas, nilai bermasalah umum dan angka ajaib, nol, -1, 1, min +/- 1, maks +/- 1, 42, nilai rnd. Jika ini tidak memberi Anda cakupan jalur, Anda tahu Anda belum menangkap semua nilai dalam analisis Anda.

Jika Anda sudah melakukan ini, Anda harus siap untuk ujian dasar ISTQB.

Surt
sumber