Come mai i compilatori sono così affidabili?

58

Usiamo i compilatori su base giornaliera come se fosse la loro correttezza, ma anche i compilatori sono programmi e possono potenzialmente contenere bug. Mi sono sempre chiesto questa infallibile robustezza. Hai mai incontrato un bug nel compilatore stesso? Cos'era e come ti sei reso conto che il problema era nel compilatore stesso?

... e in che modo fanno rendono i compilatori così affidabili?

    
posta EpsilonVector 25.02.2011 - 18:24
fonte

19 risposte

94

Vengono sottoposti a test accurati tramite l'utilizzo da parte di migliaia o addirittura milioni di sviluppatori nel tempo.

Inoltre, il problema da risolvere è ben definito (da una specifica tecnica molto dettagliata). E la natura del compito si presta facilmente ai test di unità / sistema. Cioè è fondamentalmente la traduzione di input testuali in un formato molto specifico per l'output in un altro tipo di formato ben definito (una sorta di bytecode o codice macchina). Quindi è facile creare e verificare casi di test.

Inoltre, di solito i bug sono facili da riprodurre: oltre alle informazioni esatte sulla piattaforma e sulla versione del compilatore, in genere tutto ciò che serve è un pezzo di codice di input. Per non parlare del fatto che gli utenti del compilatore (essendo essi stessi sviluppatori) tendono a fornire report dei bug molto più precisi e dettagliati di qualsiasi utente medio di computer: -)

    
risposta data 25.02.2011 - 18:28
fonte
57

Oltre a tutte le grandi risposte finora:

Hai una "distorsione da osservatore". Non si osservano bug e quindi si presume che non ce ne siano.

Ero solito pensare come te. Poi ho iniziato a scrivere compilatori professionalmente, e lascia che te lo dica, ci sono molti bug lì dentro!

Non vedi i bug perché scrivi un codice che è pari al 99,999% di tutto il resto del codice scritto dalle persone. Probabilmente scrivi un codice perfettamente normale, diretto, chiaramente corretto che chiama i metodi ed esegue cicli e non fa niente di stravagante o strano, perché sei un normale sviluppatore che risolve i normali problemi di business.

Non vedi alcun bug del compilatore perché i bug del compilatore non si trovano in semplici scenari di codice normali facili da analizzare; i bug sono nell'analisi del codice strano che non scrivi.

D'altra parte ho il pregiudizio dell'osservatore opposto. Vedo codice pazzo tutto il giorno ogni giorno, quindi per me i compilatori sembrano pieni zeppi di bug.

Se ti siedi con le specifiche del linguaggio di qualsiasi lingua, e prendi qualsiasi implementazione del compilatore per quel linguaggio, e davvero provi a determinare se il compilatore ha implementato esattamente le specifiche o meno, concentrandoti su oscuri casi d'angolo, molto presto tu " d trovare bug del compilatore abbastanza frequentemente. Lasciatemi fare un esempio, ecco un bug del compilatore C # che ho trovato letteralmente cinque minuti fa.

static void N(ref int x){}
...
N(ref 123);

Il compilatore dà tre errori.

  • Un argomento ref o out deve essere una variabile assegnabile.
  • La migliore corrispondenza per N (ref int x) ha argomenti non validi.
  • Manca "ref" sull'argomento 1.

Ovviamente il primo messaggio di errore è corretto e il terzo è un bug. L'algoritmo di generazione degli errori sta cercando di capire perché il primo argomento non è valido, lo guarda, vede che è una costante e non torna al codice sorgente per verificare se è stato contrassegnato come "ref"; piuttosto, presuppone che nessuno sarebbe abbastanza sciocco da segnare una costante come ref e decide che l'arbitro deve essere mancante.

Non è chiaro quale sia il terzo messaggio di errore corretto, ma non è così. In realtà, non è chiaro se il messaggio di errore secondo sia corretto. La risoluzione del sovraccarico dovrebbe fallire, o il "ref 123" dovrebbe essere trattato come un argomento ref di tipo corretto? Ora dovrò pensarci e discuterne con il team di triage in modo da poter determinare quale sia il comportamento corretto.

Non hai mai visto questo bug perché probabilmente non avresti mai fatto qualcosa di così stupido da provare a passare 123 per ref. E se lo facessi, probabilmente non ti accorgerai nemmeno che il terzo messaggio di errore è privo di senso, poiché il primo è corretto e sufficiente per diagnosticare il problema. Ma cerco di fare cose del genere, perché sto cercando di rompere il compilatore. Se ci hai provato, vedresti anche gli errori.

    
risposta data 01.03.2011 - 00:26
fonte
49

Mi prendi in giro? Anche i compilatori hanno bug, carichi davvero.

GCC è probabilmente il più famoso compilatore open source del pianeta e dare un'occhiata al suo database di bug: link

Tra GCC 3.2 e GCC 3.2.3 dai un'occhiata a quanti bug sono stati corretti: link

Come per altri come Visual C ++, non voglio nemmeno iniziare.

Come si rendono affidabili i compilatori? Bene, per cominciare hanno un sacco di test unitari. E l'intero pianeta li usa così senza penuria di tester.

Seriamente, gli sviluppatori di compilatori mi piace credere che siano programmatori superiori e mentre non sono infallibili fanno un bel pugno.

    
risposta data 25.02.2011 - 17:52
fonte
19

Ne ho incontrati due o tre ai miei tempi. L'unico vero modo per rilevarne uno è osservare il codice assembly.

Sebbene i compilatori siano altamente affidabili per le ragioni che altri posters hanno sottolineato, ritengo che l'affidabilità del compilatore sia spesso una valutazione che si autoavvera. I programmatori tendono a visualizzare il compilatore come standard. Quando qualcosa va storto, si presume sia colpa tua (perché è il 99,999% delle volte) e si modifica il codice per aggirare il problema del compilatore piuttosto che il contrario. Ad esempio, il codice che si arresta in modo anomalo sotto un'impostazione di ottimizzazione elevata è sicuramente un bug del compilatore, ma molte persone lo impostano un po 'più in basso e si muovono senza segnalare il bug.

    
risposta data 25.02.2011 - 17:41
fonte
13

I compilatori hanno diverse proprietà che portano alla loro correttezza:

  • Il dominio è molto noto e ricercato. Il problema è ben definito e le soluzioni offerte sono ben definite.
  • Il test automatico è sufficiente per dimostrare che i compilatori funzionano correttamente
  • I compilatori dispongono di test unitari molto ampi, in genere pubblici, automatizzati e che si sono accumulati nel tempo per coprire più spazio di errore rispetto alla maggior parte degli altri programmi
  • I compilatori hanno un numero molto grande di bulbi oculari che guardano i loro risultati
risposta data 25.02.2011 - 17:26
fonte
12

We use compilers on a daily basis

...and how do they make compilers so reliable?

Non lo fanno. Noi facciamo. Perché tutti li usano continuamente, i bug vengono trovati rapidamente.

È un gioco di numeri. Poiché i compilatori vengono utilizzati in modo così pervasivo, è altamente probabile che qualsiasi errore sarà attivato da qualcuno, ma poiché esiste un numero così elevato di utenti, è altamente improbabile quello qualcuno sarà te in particolare.

Quindi, dipende dal tuo punto di vista: su tutti gli utenti, i compilatori sono buggy. Ma è molto probabile che qualcun altro abbia compilato un codice simile prima di te, quindi se il loro era un bug, li avrebbe colpiti, non tu, quindi dal tuo individuo punto di vista, sembra che il bug non sia mai stato lì.

Naturalmente, per di più, puoi aggiungere qui tutte le altre risposte: i compilatori sono ben studiati, ben compresi. C'è questo mito che sono difficili da scrivere, il che significa che solo i programmatori molto intelligenti e molto bravi in realtà cercano di scriverne uno e sono particolarmente attenti quando lo fanno. Sono generalmente facili da testare e facili da sottoporre a stress test o fuzz test. Gli utenti del compilatore tendono a essere gli stessi programmatori esperti, portando a segnalazioni di bug di alta qualità. E viceversa: gli scrittori di compilatori tendono ad essere utenti del proprio compilatore.

    
risposta data 25.02.2011 - 18:29
fonte
11

Oltre a tutte le risposte già, vorrei aggiungere:

I credo un sacco di volte, i venditori stanno mangiando il loro cibo per cani. Significa che stanno scrivendo i compilatori da soli.

    
risposta data 25.02.2011 - 17:19
fonte
7

Ho incontrato spesso bug del compilatore.

Li puoi trovare negli angoli più bui dove ci sono meno tester. Ad esempio, per trovare bug in GCC dovresti provare:

  • Costruisci un cross-compiler. Troverai letteralmente dozzine di bug in GCC configura e costruisci script. Alcuni determinano errori di compilazione durante la compilazione GCC e altri comporteranno il fallimento del compilatore incrociato per creare file eseguibili funzionanti.
  • Crea una versione Itanium di GCC utilizzando profile-bootstrap. L'ultimo paio di volte che ho provato questo su GCC 4.4 e 4.5 non è riuscito a produrre un gestore di eccezioni C ++ funzionante. La build non ottimizzata ha funzionato bene. Nessuno sembrava interessato a correggere il bug che ho segnalato e ho rinunciato a risolverlo da solo dopo aver provato a scavare attraverso ciò che si stava rompendo nelle specifiche di memoria GCC asm.
  • Prova a creare il tuo GCJ funzionante dalle ultime novità senza seguire uno script di distribuzione della distro. Ti sfido.
risposta data 25.02.2011 - 22:33
fonte
5

Diversi motivi:

  • Gli autori di compilatori " mangiano il loro cibo per cani ".
  • I compilatori si basano su principi ben compresi di CS.
  • I compilatori sono costruiti con una chiara specifica .
  • I compilatori ricevono testato .
  • I compilatori non sono sempre molto affidabili .
risposta data 25.02.2011 - 18:10
fonte
4

Di solito sono molto bravi a -0. Infatti, se sospettiamo un bug del compilatore, confrontiamo -O0 rispetto a qualsiasi livello che stiamo cercando di utilizzare. Livelli di ottimizzazione più alti corrono maggiori rischi. Alcuni sono persino deliberatamente così, ed etichettati come tali nella documentazione. Ne ho incontrati moltissimi (almeno un centinaio durante il mio tempo), ma stanno diventando molto più rari di recente. Tuttavia, alla ricerca di buoni numeri di riferimento (o di altri parametri importanti per il marketing), la tentazione di spingere i limiti è grande. Abbiamo avuto problemi qualche anno fa, quando un fornitore (per non nominare) ha deciso di rendere la violazione delle parentesi come predefinita, piuttosto che qualche opzione di compilazione speciale chiaramente etichettata.

Può essere difficile diagnosticare un errore del compilatore rispetto a un riferimento di memoria vagante, una ricompilazione con opzioni diverse può semplicemente confondere il posizionamento relativo degli oggetti dati nella memoria, quindi non si sa se è il codice sorgente di Heisenbug, o un compilatore buggato. Inoltre, molte ottimizzazioni apportano modifiche legittime nell'ordine delle operazioni o anche semplificazioni algebriche all'algebra e queste avranno proprietà diverse rispetto all'arrotondamento in virgola mobile e all'under / overflow. È difficile districare questi effetti dai bug REALI. Il calcolo in virgola mobile con hard core è difficile per questo motivo, perché i bug e la sensibilità numerica spesso non sono facili da districare.

    
risposta data 25.02.2011 - 18:14
fonte
4

I bug del compilatore non sono così rari. Il caso più comune è che un compilatore riferisca un errore sul codice che dovrebbe essere accettato o che un compilatore accetti il codice che avrebbe dovuto essere rifiutato.

    
risposta data 25.02.2011 - 18:45
fonte
3

Sì, ho riscontrato un errore nel compilatore ASP.NET proprio ieri:

Quando si utilizzano modelli strongmente tipizzati nelle viste, esiste un limite al numero di modelli di parametri che può contenere. Ovviamente non può richiedere più di 4 parametri di template, in modo che entrambi gli esempi qui sotto lo rendano troppo per il compilatore da gestire:

ViewUserControl<System.Tuple<type1, type2, type3, type4, type5>>

Non verrebbe compilato come è ma verrà rimosso se type5 viene rimosso.

ViewUserControl<System.Tuple<MyModel, System.Func<type1, type2, type3, type4>>>

Si compilerebbe se viene rimosso type4 .

Tieni presente che System.Tuple ha molti sovraccarichi e può richiedere fino a 16 parametri (è pazzesco lo so).

    
risposta data 25.02.2011 - 17:13
fonte
3

Have you ever encountered a bug in the compiler itself? What was it and how did you realize the problem was in the compiler itself?

Yup!

I due più memorabili sono stati i primi due che ho mai incontrato. Erano entrambi nel compilatore Lightspeed C per i Mac 680x0 che risalgono al 1985-7.

Il primo era dove, in alcune circostanze, l'operatore di post-reum intero non faceva nulla - in altre parole, in un particolare pezzo di codice, "i ++" semplicemente non faceva nulla per "io". Mi stavo strappando i capelli finché non ho visto uno smontaggio. Quindi ho appena fatto l'incremento in un modo diverso e ho inviato una segnalazione di bug.

Il secondo era un po 'più complicato, ed era una "caratteristica" davvero mal considerata che andò storta. I primi Mac avevano un sistema complicato per eseguire operazioni su disco di basso livello. Per qualche ragione non ho mai capito - probabilmente dovendo creare file eseguibili più piccoli - piuttosto che compilare solo le istruzioni operative del disco sul codice dell'oggetto, il compilatore Lightspeed chiamerebbe una funzione interna, che in fase di runtime ha generato l'operazione del disco istruzioni sullo stack e saltati lì.

Questo ha funzionato benissimo su 68000 CPU, ma quando si eseguiva lo stesso codice su una CPU 68020, spesso faceva cose strane. Si è scoperto che una nuova funzionalità del 68020 era una cache di istruzioni a 256 byte di istruzione primitiva. Essendo ai primi tempi con cache della CPU, non aveva idea che la cache fosse "sporca" e necessitasse di essere ricaricata; Immagino che i progettisti di CPU di Motorola non pensassero al codice auto-modificante. Quindi, se hai eseguito due operazioni su disco abbastanza vicine nella sequenza di esecuzione e il runtime di Lightspeed ha generato le istruzioni effettive nella stessa posizione nello stack, la CPU avrebbe erroneamente pensato di avere un errore nella cache delle istruzioni ed eseguire la prima operazione del disco due volte.

Ancora una volta, immaginandoci, è stato necessario scavare con un disassemblatore e un sacco di single-stepping in un debugger di basso livello. La mia soluzione era prefissare ogni operazione del disco con una chiamata a una funzione che eseguiva 256 istruzioni "NOP", che allagava (e quindi cancellava) la cache delle istruzioni.

Da allora, da 25 anni, ho visto sempre meno errori nel compilatore nel tempo. Penso che ci siano un paio di ragioni per questo:

  • Esiste un insieme sempre crescente di test di convalida per i compilatori.
  • I compilatori moderni sono in genere divisi in due o più parti, una delle quali genera codice indipendente dalla piattaforma (ad esempio il targeting di LLVM che potresti considerare una CPU immaginaria) e un'altra che la traduce in istruzioni per l'hardware di destinazione effettivo. Nei compilatori multipiattaforma, la prima parte viene utilizzata ovunque, quindi ottiene tonnellate di test nel mondo reale.
risposta data 25.02.2011 - 22:16
fonte
3

Trovato un errore lampante in Turbo Pascal 5.5 anni fa. Un errore presente nella versione precedente (5.0) né nella successiva (6.0) del compilatore. E uno che avrebbe dovuto essere facile da testare, in quanto non era affatto una cornetta (solo una chiamata che non è quella comunemente usata).

In generale, sicuramente i costruttori di compilatori commerciali (piuttosto che i progetti di hobby) avranno procedure di controllo qualità e procedure di test molto ampie. Sanno che i loro compilatori sono i loro progetti di punta e che i difetti saranno molto negativi su di loro, peggio di quanto sembrerebbero alle altre società che realizzano la maggior parte degli altri prodotti. Gli sviluppatori di software sono un gruppo imperdonabile, i nostri fornitori di strumenti ci deludono, è probabile che andiamo a cercare alternative piuttosto che aspettare una correzione da parte del fornitore e siamo molto propensi a comunicarlo ai nostri colleghi che potrebbero seguire bene il nostro esempio. In molti altri settori questo non è il caso, quindi la perdita potenziale per un produttore di compilatori a causa di un bug grave è di gran lunga superiore a quella di un produttore di software di editing video.

    
risposta data 01.03.2011 - 08:26
fonte
2

Quando il comportamento del tuo software è diverso quando compilato con -O0 e con -O2, hai trovato un bug del compilatore.

Quando il comportamento del tuo software è solo diverso da quello che ti aspetti, è probabile che il bug sia presente nel tuo codice.

    
risposta data 25.02.2011 - 17:40
fonte
2

I bug del compilatore si verificano, ma tendi a trovarli in angoli strani ...

C'era uno strano bug nel compilatore VAX VMS C della Digital Equipment Corporation negli anni '90

(Indossavo una cipolla alla cintura, come al solito la moda)

Un punto e virgola estraneo dovunque prima di un ciclo for verrà compilato come corpo del ciclo for.

f(){...}
;
g(){...}

void test(){
  int i;
  for ( i=0; i < 10; i++){
     puts("hello");
  }
}

Sul compilatore in questione, il ciclo viene eseguito solo una volta.

vede

f(){...}
g(){...}

void test(){
  int i;
  for ( i=0; i < 10; i++) ;  /* empty statement for fun */

  {
     puts("hello");
  }
}

Questo mi è costato un sacco di tempo.

La versione precedente del compilatore PIC C che (usato per) infligge agli studenti di esperienza lavorativa non è stato in grado di generare codice che usasse correttamente l'interrupt ad alta priorità. Hai dovuto aspettare 2-3 anni e aggiornare.

Il compilatore MSVC 6 aveva un bell'errore nel linker, sarebbe guasto di segmentazione e morirà di volta in volta senza motivo. Generalmente una build pulita la risolveva (ma sigh non sempre).

    
risposta data 28.02.2011 - 23:31
fonte
2

In alcuni domini, come il software avionico, ci sono requisiti di certificazione estremamente elevati, sul codice e sull'hardware, nonché sul compilatore. A proposito di quest'ultima parte, c'è un progetto che mira a creare un compilatore C verificato formalmente, chiamato Compcert . In teoria, questo tipo di compilatore è affidabile come viene.

    
risposta data 23.10.2018 - 03:27
fonte
1

Ho visto diversi bug del compilatore, ne ho segnalato alcuni (in particolare in F #).

Detto questo, penso che i bug del compilatore siano rari perché le persone che scrivono compilatori sono generalmente molto a proprio agio con i rigorosi concetti di informatica che li rendono veramente consapevoli delle implicazioni matematiche del codice.

Molti di loro hanno presumibilmente molta familiarità con cose come il lambda calcolo, la verifica formale, la semantica denotazionale ecc. - cose che un programmatore medio come me riesce a comprendere a malapena.

Inoltre, di solito c'è una mappatura piuttosto semplice dall'input all'output nei compilatori, quindi il debug di un linguaggio di programmazione è probabilmente molto più semplice del debugging, ad esempio, di un motore di blog.

    
risposta data 25.02.2011 - 22:32
fonte
1

Ho trovato un bug nel compilatore C # non molto tempo fa, puoi vedere come Eric Lippert (che è nel team di progettazione C #) ha capito quale fosse il bug qui .

Oltre alle risposte già fornite, vorrei aggiungere alcune altre cose. I progettisti di compilatori sono spesso ottimi programmatori. I compilatori sono molto importanti: la maggior parte della programmazione viene eseguita utilizzando i compilatori, quindi è imperativo che il compilatore sia di alta qualità. È quindi nell'interesse delle aziende che fanno compilatori per mettere le loro persone migliori su di esso (o almeno, molto buone: le migliori potrebbero non gradire il design del compilatore). Microsoft vorrebbe che i compilatori C e C ++ funzionassero correttamente, o il resto dell'azienda non può svolgere il proprio lavoro.

Inoltre, se stai costruendo un compilatore davvero complesso, non puoi semplicemente modificarlo. La logica dietro i compilatori è al contempo estremamente complessa e facile da formalizzare. Quindi, questi programmi saranno spesso costruiti in un modo molto "robusto" e generico, che tende a provocare meno errori.

    
risposta data 23.05.2017 - 14:40
fonte

Leggi altre domande sui tag