Come possiamo essere certi che i componenti inferiori della programmazione del computer come compilatori, assemblatori, istruzioni di macchine, ecc. Siano impeccabili?


57

Dato che stiamo diventando sempre più dipendenti dall'informatica, compresi i compiti molto critici della vita quotidiana, mi stavo solo chiedendo come vengono testati quei componenti vitali.

Più tecnicamente, come vengono testati i compilatori e gli assemblatori? (Suppongo che ciò si riferisca al problema dell'arresto !!)


36
Potresti voler iniziare la tua ricerca con "Ken Thompson Hack" Vedi le riflessioni sul Trusting Trust
Bryan Oakley,

7
Ecco un esempio di compilatore per il quale esiste una prova di correttezza: compcert.inria.fr/doc/index.html
Giorgio,

8
La maggior parte dei compilatori / linker / assemblatori vengono testati in modo più approfondito utilizzandoli molto in molte circostanze diverse. Per trovare errori, non c'è niente di meglio che milioni di utenti utilizzino il tuo compilatore.
Bart van Ingen Schenau,

3
e aggiungi anche il sistema operativo all'elenco.
Erik Eidt,

Risposte:


104

Non puoi esserne certo, ma supponi che lo siano, finché non scopri che non lo sono. Nel corso degli anni ci sono stati molti bug nei compilatori e nell'hardware.

Il modo in cui questi vengono testati, ad esempio un compilatore, è che sono definiti in modo molto stretto e rigido, scritti con cura, quindi testati con un'enorme suite di test per verificarne la correttezza. Aggiungete a ciò l'ampia base di utenti di un compilatore e verranno rilevati e segnalati più bug. Un'app di pianificazione degli appuntamenti dal dentista, comparativamente, ha molti meno utenti e ancora meno in grado di rilevare difetti.

SQLite è costituito da circa 73k righe di codice, mentre la sua suite di test è composta da circa 91378k righe di codice, oltre 1250 volte quella di SQLite stesso. Mi aspetto che i compilatori e altri strumenti di base abbiano rapporti simili. I processori oggi sono progettati essenzialmente con software, usando linguaggi di descrizione hardware come Verilog o VHDL, e quelli hanno anche test del software eseguiti su di essi, così come pin IO specializzati per eseguire autotest nel punto di produzione.

Alla fine è un gioco di probabilità, e test ripetuti e ampiamente coprenti consentono di spingere la probabilità di difetti a un livello accettabilmente basso, lo stesso di un altro progetto software.


7
Mi sono spesso posto la stessa domanda dell'OP, ma per quanto riguarda i DBMS. Hai fornito un ottimo esempio che ha risposto nel contesto di SQLite. Grazie!
Brandon,

7
+1 ma in qualche modo dubito che "i compilatori e altri strumenti di base abbiano rapporti simili".
Mehrdad,

5
Si noti che (1) SQLite ha in realtà due test suite, con ridondanza non banale tra i due e (2) ci sono ancora dei bug trovati in SQLite nonostante questo.
Matthieu M.

7
Ho avuto l'impressione che SQLite sia uno dei software più "ampiamente testati" (in termini di linee di codice di test / linee di codice operativo) disponibili per l'uso generale, più che di molti compilatori. Se non altro, un compilatore con funzionalità complete è un enorme software e non riesco a immaginare che abbia un numero di volte superiore a tale codice di test. (Secondo quanto riferito, GCC ha un massimo di 14,5 milioni di righe. Sembra improbabile che la raccolta di compilatori sia solo 14k LOC, o che abbiano un codebase di test da 14 miliardi di righe seduto sul lato! :-P)
David Z

2
@DavidZ: Sì, è certamente l'unico progetto che conosco, ad esempio, ad utilizzare test OOM approfonditi (usano un iniettore di guasti per il test e li riproducono ancora e ancora fallendo al 1 °, quindi 2 ° allocazione ... fino all'intero test viene eseguito).
Matthieu M.

46

In parole povere:

  1. Non puoi.
  2. Compilatori e interpreti sono testati in unità come qualsiasi altro software (professionale).
  3. Un test riuscito non significa che un programma sia privo di bug, significa solo che non sono stati rilevati bug.
  4. Un'ampia base di utenti che utilizza il compilatore per un lungo periodo è un chiaro indicatore del fatto che ha pochissimi bug, perché gli utenti di solito testano casi a cui i progettisti non hanno pensato.
  5. Essere open source è anche un buon indicatore. "Dato un numero sufficiente di bulbi oculari, tutti i bug sono poco profondi ... Data una base beta-tester e co-sviluppatore abbastanza grande, quasi tutti i problemi saranno caratterizzati rapidamente e la correzione sarà ovvia per qualcuno." . Un compilatore a sorgente chiuso potrebbe avere bug che si presentano in momenti molto specifici o che generano un codice macchina non ottimale e la società dietro di esso potrebbe semplicemente non rivelare la propria esistenza e dargli una priorità molto bassa nella road map del prodotto.

Linea di fondo:

Direi di optare per OOP ( O ld, O pen e P opular). Ho appena inventato quell'acronimo.


19
+1 Per aver inventato un altro TLA (acronimo di tre lettere) - il mondo non ne ha ancora abbastanza di quelli.
s1lv3r,

34
Inoltre, OOP non aveva ancora alcun significato nella programmazione del computer. Quindi KTT (complimenti a te)!
Pierre Arlaud,

15
Il commento di Pierre è uno scherzo @Dannnno.
yannis,

19
In alternativa, potrebbe usare P opular, O ld e O pen. ;) In realtà, è così che li classificherei in ordine di importanza.
jpmc26,

23
@ jpmc26 Vorrei andare con Pratico, Vecchio, Aperto e Popolare. Per quanto riguarda l'acronimo ...
StupidOne

24

Sono le tartarughe fino in fondo.

Niente è certo. Non hai altra scelta se non quella di affidarti a valutazioni di fiducia.

Puoi pensarlo come uno stack: Matematica> Fisica> Hardware> Firmware> Sistema operativo> Assembler / Compiler / etc

Ad ogni livello hai dei test che puoi eseguire per migliorare i tuoi voti di fiducia. Alcuni di questi test hanno la qualità di prove formali, alcuni si basano sull'osservazione, la maggior parte sono una combinazione di entrambi.

La parte difficile è svelare la ricorsione in alcuni di questi test perché usiamo i programmi per fare prove e analisi osservazionali ora dove è diventato troppo difficile farlo a mano.

Alla fine, però, la risposta è che provi tutto ciò che ti viene in mente. Analisi statica, fuzzing, simulazione, esecuzione con input estremi o input casuali appositamente selezionati, esecuzione / mappatura di ogni percorso di controllo, prove formali, ecc. Fondamentalmente il tuo obiettivo nei test dovrebbe essere sempre quello di fare tutto il possibile per dimostrare che il tuo prodotto (es. Teoria / chip / programma) non funziona come previsto. Se fai uno sforzo genuino e ancora fallisci, ti è permesso migliorare il tuo grado di fiducia nella correttezza del tuo prodotto.

Il test è nella migliore delle ipotesi un processo di semidecisione, il che significa che dato che c'è un bug alla fine lo troverai ma non puoi mai essere sicuro di averli trovati tutti. Anche con un software verificato formalmente fai ancora affidamento sulla fisica, sugli strumenti utilizzati per fare le prove formali e che la cosa che hai dimostrato è necessaria e sufficiente per il tuo programma per fare ciò che è (spesso soggettivamente) "inteso". Questo per non parlare di tutti gli altri componenti che stai usando che non hanno prove formali.


17

Questa è una domanda "pericolosa" per i nuovi sviluppatori in quanto inizieranno a incolpare i loro strumenti invece del loro codice (stato lì, fatto, visto che troppi lo fanno). Sebbene ci siano bug nei compilatori, negli ambienti di runtime, nel sistema operativo, ecc., Gli sviluppatori dovrebbero essere realistici e ricordare che, fino a quando non ci saranno prove e unit test che dimostrano il contrario, il bug è nel tuo codice .

In oltre 25 anni di programmazione principalmente in C, C ++ e Java ho scoperto:

  • due bug dovuti a un bug del compilatore (gcc e SunOS C)
  • circa una volta all'anno o due un bug a causa di un problema Java JVM (generalmente correlato al consumo di memoria / garbage collection)
  • circa una volta al mese o due un bug in una libreria, che spesso viene risolto utilizzando la versione più recente o ripristinando la versione precedente della libreria

Tutti gli altri bug sono direttamente correlati a un bug o, più frequentemente, alla mancanza di comprensione del funzionamento di una libreria. A volte ciò che sembra essere un bug è dovuto a un'incompatibilità, ad esempio come è cambiata la struttura della classe Java che ha rotto alcune librerie AOP.


Sono curioso: quali anni per quali lingue? Ai tempi dell'EGCS prima che il C ++ fosse correttamente standardizzato, i bug del compilatore non erano così difficili da trovare ...
Charles Duffy,

3
Più oscuro è il compilatore, la cpu o la lingua, più facile è trovare un bug nei compilatori (prima di qualcun altro), quindi trovare 2 in GCC C è bello :)
Surt

1
A quanto pare, ho appena perso un mese a presumere che il problema che stavo avendo era nei miei script gdb, o la mia comprensione di ciò che stavo esaminando. Alla fine sono diventato sospettoso, ho semplificato il mio caso di test e ho trovato un difetto di progettazione in una libreria (libkvm), che ha reso un debugger del kernel impossibile accedere a determinati indirizzi da un dump principale. Vale a dire YMMV - e sono più felice quando trovo un nuovo bug nel codice a monte di me, specialmente qualcosa che sto usando piuttosto che sviluppare.
Arlie Stephens,

Ovviamente non si trattava di un bug del compilatore o di una delle librerie più comunemente utilizzate. E a dire il vero, non trovo bug in quelli con nessuna frequenza.
Arlie Stephens,

@ArlieStephens C'è una lezione qui: semplificare il tuo test è qualcosa che dovresti fare presto quando non riesci a trovare un problema. Indipendentemente dal fatto che il problema sia tuo o dell'altro codice, ciò ti aiuterà a restringerlo. Spesso, se il problema è nell'altro codice, ciò comporterà "prove e unit test dimostrativi".
jpmc26

8

Penso che un punto interessante qui sia che la stragrande maggioranza delle licenze di software commerciale (e in effetti di software open source) specifica specificamente che non puoi fidarti del software.

IL SOFTWARE È FORNITO "COSÌ COM'È", SENZA ALCUN TIPO DI GARANZIA, ESPRESSA O IMPLICITA, COMPRESO MA NON LIMITATO ALLE GARANZIE DI COMMERCIABILITÀ, IDONEITÀ PER UNO SCOPO PARTICOLARE E NON VIOLAZIONE.

Dal contratto di licenza di Microsoft Word

. Fatta eccezione per la Garanzia limitata e nella misura massima consentita dalla legge applicabile, Microsoft e i suoi fornitori forniscono il Software e i servizi di supporto (se presenti) COSÌ COME SONO E CON TUTTI I GUASTI, e con la presente declinano ogni altra garanzia e condizione, espressa, implicita o statutario, incluse, a titolo esemplificativo, garanzie (doveri) implicite, doveri o condizioni di commerciabilità, idoneità per uno scopo particolare, affidabilità o disponibilità, accuratezza o completezza delle risposte, dei risultati, dello sforzo professionale, di mancanza di virus e mancanza di negligenza, tutti in relazione al Software e la fornitura o la mancata fornitura di supporto o altri servizi, informazioni, software e contenuti correlati attraverso il Software o derivanti in altro modo dall'uso del Software .

In sostanza questa frase nella licenza in quasi tutti i software che usi specifica ti dice che non puoi fidarti del software e tanto meno del compilatore usato.

Il software è come una teoria scientifica, si ritiene che funzioni come specificato fino a quando non lo fa.


+1 per sottolineare che le stesse licenze affermano che nessun software è perfetto.
Tulains Córdova,

3
Sono stato felice di notare una deviazione da questa pratica in ViaVoice per Mac di IBM. Invece del solito "se non funziona, peccato" in realtà hanno detto qualcosa come "Il software è garantito per funzionare come specificato".
WGroleau,

1
Una traduzione in un linguaggio semplice di questo particolare frammento di garanzia è: "Questo potrebbe essere un software o potrebbe essere un pezzo di merda. Potrebbe funzionare. Potrebbe non funzionare. Anche se funziona potrebbe non fai quello che vuoi. Oh, a proposito, potremmo averlo rubato a qualcun altro. Peccato. Abbiamo i tuoi soldi e li abbiamo usati per assumere molti avvocati. GIOCO! ON! Nyah-nyah -nyah-Nyah-nyaaah-naah!". :-)
Bob Jarvis il

2
@BobJarvis: La mia dichiarazione di garanzia preferita, utilizzata su alcuni software open source (come nmap IIRC), è "Se si rompe, riesci a conservare entrambi i pezzi".
Peter Cordes,

Questa affermazione è onnipresente nel software open source e in molti software open source gratuiti. Non appare nella maggior parte delle licenze software commerciali a pagamento.
JWG

2

Come autore di compilatori per un linguaggio matematico *, dalla mia esperienza posso dire in teoria che non puoi. E alcuni dei bug danno solo risultati errati come (dalla mia lista della vergogna) calcolando 6/3*2da destra 6/(3*2)e producendo 1 senza crash o dando errori di compilazione senza senso.

Ma IMHO molti compilatori non hanno tanti bug quanti altri software perché:

  • Scrivere test unitari è facile. Ogni istruzione è un'unità ed è possibile scrivere test semplici come:test_unit("2+(-2)*(-2+1)*3+1",9);
  • Un programma è una combinazione di istruzioni e per ogni programma di produrre il risultato corretto ogni singola istruzione deve dare il risultato corretto (principalmente). Quindi è molto improbabile che ci siano dei bug mentre il programma fornisce il risultato corretto.
  • Con l'aumentare delle dimensioni e del numero di programmi scritti, aumenta notevolmente la probabilità di catturare bug.

Per gli assemblatori, le istruzioni della macchina ecc., Vale anche quanto sopra; d'altra parte la verifica e la validazione nella progettazione e produzione di chip hanno processi molto più severi poiché si tratta di un grande business: automazione della progettazione elettronica .

Prima di andare in produzione ogni CPU dovrebbe essere testata rigorosamente perché ogni bug costa quasi un paio di milioni di dollari: ci sono enormi costi di produzione non ricorrenti nella produzione di chip. Quindi le aziende spendono un sacco di soldi e scrivono molti codici di simulazione per il loro design prima di iniziare la produzione, anche se questo non offre una garanzia del 100%, ad esempio il bug Pentium FDIV.

In breve, è molto improbabile che si verifichino gravi bug in compilatori, codici macchina ecc.

La mia umile lingua matematica *


Intel mette alla prova le loro CPU eseguendo sequenze di istruzioni casuali e confrontando con un modello software, tra le altre cose: tweakers.net/reviews/740/4/… . Questo è il motivo per cui spesso vengono pubblicati errata davvero oscuri, per alcune combinazioni di istruzioni davvero improbabili in una modalità insolita.
Peter Cordes,

0

Flawless? Loro non sono. Di recente ho installato alcuni "aggiornamenti", e sono passati mesi (e diverse sezioni di codice riprogrammate) più tardi prima che il mio sito ASP.NET funzionasse di nuovo correttamente, a causa di cambiamenti inspiegabili nel modo in cui varie cose di base funzionavano o fallivano.

Tuttavia, vengono testati e quindi utilizzati da molte persone molto intelligenti e orientate ai dettagli, che tendono a notare, segnalare e risolvere la maggior parte delle cose. Stack Exchange è un ottimo esempio (e miglioramento) del modo in cui tutte le persone che usano questi strumenti aiutano a testare e analizzare il funzionamento di questi strumenti incredibilmente complessi e di basso livello, almeno per quanto riguarda l'uso pratico.

Ma impeccabile, no. Sebbene sia possibile vedere anche le persone su Stack Exchange ottenere una visione impressionante dei dettagli sulle prestazioni, conformità agli standard e stranezze, ci sono sempre difetti e imperfezioni, specialmente quando persone diverse hanno opinioni diverse su cosa sia un difetto.


-1

Per mostrare che anche i sistemi sottostanti sono impeccabili

a) È necessario provare che sono impeccabili

  1. Prova matematica
  2. Realisticamente possibile solo per programmi banali

b) Effettuare un test esaustivo

  1. Possibile solo per programmi banali e alcuni programmi semplici
  2. Non appena un elemento di temporizzazione entra nel test, non è possibile effettuare un test esauriente in quanto il tempo può essere diviso indefinitamente.
  3. Oltre ai banali programmi, le possibili opzioni di esecuzione esplodono in modo esponenziale.

Nei test software il test esaustivo viene utilizzato solo nel test unitario di alcune semplici funzioni.

Esempio: vuoi testare un input utf-8 di 8 caratteri in un campo, fai la scelta di tagliare l'input a 8 volte la lunghezza massima 6 di utf-8 in byte che dà 8 * 6 = 48 byte per avere effettivamente un quantità finite di possibilità.

Ora potresti pensare di dover solo testare i 1.112.064 punti di codice validi di ciascuno degli 8 caratteri, ad es. 1.112.064 ^ 8 (diciamo 10 ^ 48) test (che è già improbabile sia possibile), ma in realtà devi testare ogni valore di ciascuno dei 48 byte o 256 ^ 48 che è circa 10 ^ 120 che è la stessa complessità degli scacchi rispetto al numero totale di atomi nell'universo di circa 10 ^ 80.

Invece puoi usare, in ordine crescente di sforzo e ogni test dovrebbe coprire tutto il precedente:

a) testare un campione buono e uno cattivo.

b) copertura del codice, ad es. prova a testare ogni riga di codice, che è relativamente semplice per la maggior parte del codice. Ora puoi chiederti quale sia l'ultimo 1% del codice che non puoi testare c'è ... bug, codice morto, eccezioni hardware ecc.

c) copertura del percorso, vengono testati tutti i risultati di tutti i rami in tutte le combinazioni. Ora sai perché il reparto test ti odia quando le tue funzioni contengono più di 10 condizioni. Inoltre ti chiedi perché l'ultimo 1% non possa essere testato ... alcuni rami dipendono dai rami precedenti.

d) test dei dati, test di un numero di campione con valore del bordo, valori problematici comuni e numeri magici, zero, -1, 1, min +/- 1, max +/- 1, 42, rnd valori. Se ciò non ti fornisce la copertura del percorso, sai che non hai colto tutti i valori della tua analisi.

Se lo fai già, dovresti essere pronto per l'esame di fondazione ISTQB.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.