"Hai mai cambiato il valore di 4?" - come è arrivato nel quiz Hayes-Thomas?


24

Nel 1989 Felix Lee, John Hayes e Angela Thomas scrissero un test di hacker prendendo la forma di un quiz con molte battute da insider, come " Mangi muffe di melma?

Sto considerando le seguenti serie:

0015 Ever change the value of 4?
0016 ... Unintentionally?
0017 ... In a language other than Fortran?

C'è un particolare aneddoto che rende il numero “4” particolare nella serie?

Qualche implementazione di Fortran ha permesso di modificare il valore delle costanti? Questo era possibile in altre lingue di uso comune in quel momento?


2
@Ordous Non mi dispiace se manteniamo la seconda domanda qui, soprattutto se i rispondenti si preoccupano di spiegare perché un tale comportamento esiste nelle lingue moderne (cioè ci sono usi pratici per esso?). Detto questo, sarebbe anche un'ottima domanda per Code Golf .
yannis,

8
Correlati: scrivere un programma che fa 2 + 2 = 5 . A Java e Python Risposte Non ci sostituire 4per 5le liste di interi internati.
Martijn Pieters,

5
E un commento su quella pagina afferma che potresti ridefinire i letterali in FORTRAN IV; 4 = 5era possibile.
Martijn Pieters,

7
E grazie per il link di prova di quell'Hacker. Ora mi hai fatto sentire vecchio, oltre che inorridito da quanto spesso potevo rispondere "sì" alle domande.
Martijn Pieters,

5
Ho cambiato una volta il valore dello zero costante in un programma fortran. È stato un bug molto difficile da rintracciare.
Bryan Oakley,

Risposte:


32

Ai vecchi tempi (anni '70 e precedenti) alcuni computer non avevano MMU (e questo è vero oggi per i microcontrollori molto economici).

Su tali sistemi, non esiste una protezione della memoria, quindi nessun segmento di sola lettura nello spazio degli indirizzi e un programma con errori potrebbe sovrascrivere una costante (nella memoria dati o persino all'interno del codice macchina).

I compilatori Fortran a quel tempo passarono argomenti formali per riferimento . Quindi, se lo hai fatto CALL FUN(4)e il SUBROUTINE FUN(I)suo corpo cambia I, ad esempio con un'affermazione I = I + 1nel suo corpo, potresti avere un disastro, cambiando 4 in 5 nel chiamante (o peggio).

Ciò valeva anche per i primi microcomputer come l' IBM PC AT originale del 1984, con MS-DOS

FWIW, sono abbastanza vecchio da aver usato, come un adolescente nei primi anni '70, computer del genere: IBM1620 e CAB500 (in un museo: questi sono computer dell'era degli anni '60!). L'IBM1620 era piuttosto divertente: veniva usato nelle tabelle di memoria per aggiunte e moltiplicazioni (e se sovrascrivevi queste tabelle, ne conseguiva il caos). Quindi non solo potresti sovrascrivere un 4, ma potresti anche sovrascrivere ogni futura aggiunta 2 + 2 o moltiplicazioni 7 * 8 (ma ho davvero dimenticato questi dettagli sporchi, quindi potrebbe essere sbagliato).

Oggi potresti sovrascrivere il codice BIOS nella memoria flash, se sei abbastanza perseverante. Purtroppo, non mi sento più così divertente, quindi non ci ho mai provato. (Ho anche paura di installare alcuni LinuxBios sulla mia scheda madre).

Sui computer e sistemi operativi attuali il passaggio di una costante come riferimento e la modifica all'interno della chiamata provocherà semplicemente una violazione della segmentazione , che risulta familiare a molti sviluppatori C o C ++.

A proposito: essere pignoli: sovrascrivere 4 non è una questione di linguaggio, ma di implementazione.


14
Il 1620 fu soprannominato CADET: impossibile aggiungere, nemmeno provare.
Pete Becker,

Il trucco può essere quasi ripetuto anche adesso con gfortran. Le costanti vengono inserite nel loro segmento e passate facendo riferimento a una subroutine. Per impostazione predefinita, la sezione costante è di sola lettura, quindi l'errore di protezione della memoria uccide il programma.
Netch

7

È stato un effetto collaterale involontario della strategia di valutazione delle chiamate di funzione FORTRAN in combinazione con un'ottimizzazione del compilatore errata.

FORTRAN II ha introdotto funzioni e subroutine definite dall'utente con i loro argomenti passati per riferimento . (Perché, non lo so. Probabilmente era più efficiente del valore pass-by sull'hardware IBM dell'epoca.)

Normalmente, pass-by-reference significa che devi passare un valore l (come una variabile) invece di un valore r. Ma i progettisti di FORTRAN hanno deciso di essere d'aiuto e di lasciarti comunque passare valori-r come argomenti. Il compilatore genererebbe automaticamente una variabile per te. Quindi, se hai scritto:

CALL SUBFOO(X + Y, 4)

il compilatore lo convertirà dietro le quinte in qualcosa del genere

TEMP1 = X + Y
TEMP2 = 4
CALL SUBFOO(TEMP1, TEMP2)

C'era anche una comune ottimizzazione del compilatore chiamata "pool letterale", che avrebbe consolidato più istanze della stessa costante numerica nella stessa variabile generata automaticamente. (Diverse lingue della famiglia C richiedono questo per i letterali stringa.) Quindi, se hai scritto

CALL SUBBAR(4)
CALL SUBBAZ(4)

questo sarebbe trattato come se fosse

FOUR = 4
CALL SUBBAR(FOUR)
CALL SUBBAZ(FOUR)

che sembra una cosa perfettamente ragionevole da fare fino a quando non si ha un sottoprogramma che modifica il valore dei suoi parametri.

SUBROUTINE SUBBAR(X)
    !...lots of code...
    X = 5
    !...lots of code...
END SUBROUTINE SUBBAR

Boom! CALL SUBBAR(4)ha cambiato il valore di 4 nel pool letterale in 5. E poi ti stai chiedendo perché SUBBAZstai assumendo di averlo passato un 5 invece di quello che 4hai effettivamente scritto nel codice.

Le versioni più recenti di Fortran mitigano questo problema consentendo di dichiarare la INTENTvariabile come INo OUTe dandoti un errore (o almeno un avviso) se passi una costante come OUTparametro.


5

In FORTRAN, quando una costante viene passata a un'altra procedura, non viene più protetta. Questo è ciò a cui si riferiscono. Altri linguaggi di programmazione popolari in quel periodo erano C e Pascal che non avevano (e ancora non hanno) questo problema. Forse ci sono linguaggi di programmazione più vecchi di cui non sono a conoscenza che hanno lo stesso problema.


Inoltre, si riferisce al fatto che il pool costante non si trovava in un segmento di sola lettura. In tal caso, e 4 viene passato per riferimento e modificato dalla chiamata, SEGV si verificherebbe senza cambiare con successo 4.
Basile Starynkevitch

Questo perché non tutti i sistemi operativi avevano un segmento di sola lettura. La trappola potrebbe essere usata su DOS, ad esempio, i sistemi operativi con segmenti di sola lettura (usando la memoria virtuale) come UNIX restituirebbero un errore di segmentazione in fase di esecuzione. Comunque, il compilatore non dovrebbe permetterlo.
dj bazzie wazzie,

4
Mi manca Pascal :(
Gareth,

1
Per essere più specifici, FORTRAN passa per riferimento. Quindi, se si passa una costante come parametro di funzione, è possibile modificare quel valore per ogni uso di quel numero.
Gabe,

1
Solo se quella costante (passata per riferimento) rimane in un segmento di lettura-scrittura. Se si trova in un .rodatasegmento di sola lettura (come fanno i compilatori attuali), la modifica non modificherà la costante ma causerebbe un SEGV.
Basile Starynkevitch,
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.