Wie kam es zum Hayes-Thomas-Quiz?

24

1989 schrieben Felix Lee, John Hayes und Angela Thomas einen Hacker-Test in Form eines Quiz mit vielen Insider-Witzen: „ Isst du Schleimpilze? "

Ich überlege mir folgende serie:

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

Gibt es eine bestimmte Anekdote, die die Zahl „4“ in der Serie besonders macht?

Konnte bei einigen Fortran-Implementierungen der Wert von Konstanten geändert werden? War dies in anderen damals gebräuchlichen Sprachen möglich?

Michael Le Barbier Grünewald
quelle
2
@Ordous Es macht mir nichts aus, wenn wir die zweite Frage hier behalten, insbesondere wenn die Antwortenden sorgfältig erklären, warum ein solches Verhalten in modernen Sprachen existiert (dh gibt es einen praktischen Nutzen dafür?). Das heißt, es wäre auch eine ausgezeichnete Code Golf Frage.
Yannis
8
Verwandte: Schreiben Sie ein Programm, das 2 + 2 = 5 macht . Ein Java und Python Antworten dort ersetzen 4für 5in den internierten ganzen Zahlen - Listen.
Martijn Pieters
5
Ein Kommentar auf dieser Seite besagt, dass Sie Literale in FORTRAN IV neu definieren können. 4 = 5war möglich.
Martijn Pieters
7
Und danke für den Testlink von Hacker. Sie haben mich jetzt alt und entsetzt darüber, wie oft ich die Fragen mit "Ja" beantworten konnte.
Martijn Pieters
5
Ich habe den Wert der Konstanten Null in einem fortran-Programm einmal geändert. Das war ein sehr schwieriger Fehler.
Bryan Oakley

Antworten:

32

In den alten Tagen (1970er und früher) hatten einige Computer keine MMU (und dies gilt heute für sehr billige Mikrocontroller).

Auf solchen Systemen gibt es keinen Speicherschutz, so dass kein Nur-Lese-Segment im Adressraum vorhanden ist und ein fehlerhaftes Programm eine Konstante überschreiben kann (entweder im Datenspeicher oder sogar im Maschinencode).

Die damaligen Fortran-Compiler führten formelle Argumente als Referenz durch . Wenn Sie dies getan haben CALL FUN(4)und sich der SUBROUTINE FUN(I)Körper von geändert hat, Iz. B. mit einer Aussage I = I + 1im Körper, könnte es zu einer Katastrophe kommen, bei der der Anrufer von 4 zu 5 wechselt (oder noch schlimmer).

Dies galt auch für die ersten Mikrocomputer wie den ursprünglichen IBM PC AT von 1984 mit MS-DOS

FWIW, ich bin alt genug, um als Teenager Anfang der 1970er Jahre solche Computer zu benutzen: IBM1620 und CAB500 (in einem Museum: das sind Computer aus den 1960er Jahren!). Der IBM1620 hat Spaß gemacht: Er wurde in Speichertabellen für Additionen und Multiplikationen verwendet (und wenn Sie diese Tabellen überschrieben, kam es zu Chaos). Sie könnten also nicht nur eine 4 überschreiben, sondern auch jede zukünftige 2 + 2-Addition oder 7 * 8-Multiplikation (aber ich habe diese schmutzigen Details wirklich vergessen und könnte daher falsch sein).

Heute könnten Sie den BIOS-Code im Flash-Speicher überschreiben, wenn Sie ausdauernd genug sind. Leider finde ich das nicht mehr lustig, also habe ich es nie versucht. (Ich habe sogar Angst, LinuxBios auf meinem Motherboard zu installieren).

Wenn auf aktuellen Computern und Betriebssystemen eine Konstante als Referenz übergeben und in der Aufgerufenen geändert wird, tritt lediglich eine Segmentierungsverletzung auf , die vielen C- oder C ++ - Entwicklern geläufig ist.

Übrigens: Nicht auswählen: Das Überschreiben von 4 ist keine Frage der Sprache, sondern der Implementierung.

Basile Starynkevitch
quelle
14
Der 1620 erhielt den Spitznamen CADET: Kann nicht hinzufügen, versucht es nicht einmal.
Pete Becker
Der Trick kann schon jetzt mit fast wiederholt werden gfortran. Konstanten werden in ihr Segment eingefügt und als Referenz an ein Unterprogramm übergeben. Standardmäßig ist der konstante Abschnitt schreibgeschützt, sodass ein Speicherschutzfehler das Programm beendet.
Netch
7

Dies war ein unbeabsichtigter Nebeneffekt der Funktionsaufruf-Bewertungsstrategie von FORTRAN in Kombination mit einer fehlerhaften Compiler-Optimierung.

FORTRAN II führte benutzerdefinierte Funktionen und Unterprogramme mit ihren als Referenz übergebenen Argumenten ein . (Ich weiß nicht, warum. Es war wahrscheinlich effizienter als die Weitergabe von Werten auf IBM-Hardware der Zeit.)

Normalerweise bedeutet Referenzübergabe, dass Sie einen l-Wert (wie eine Variable) anstelle eines r-Werts übergeben müssen. Die Designer von FORTRAN haben sich jedoch dazu entschlossen, hilfreich zu sein und Sie trotzdem r-Werte als Argumente übergeben zu lassen. Der Compiler generiert automatisch eine Variable für Sie. Also, wenn Sie geschrieben haben:

CALL SUBFOO(X + Y, 4)

Der Compiler würde dies hinter den Kulissen in so etwas wie konvertieren

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

Es gab auch eine allgemeine Compiler-Optimierung, die als "Literal-Pool" bezeichnet wurde und mehrere Instanzen derselben numerischen Konstante in derselben automatisch generierten Variablen zusammenfasste. (Einige Sprachen in der C-Familie erfordern dies für Zeichenkettenliterale.) Also, wenn Sie geschrieben haben

CALL SUBBAR(4)
CALL SUBBAZ(4)

Dies würde so behandelt, als ob es wäre

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

Das scheint eine vernünftige Sache zu sein, bis Sie ein Unterprogramm haben, das den Wert seiner Parameter ändert.

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

Boom! CALL SUBBAR(4)änderte den Wert der 4 im Literal-Pool in eine 5. Und dann wundern Sie sich, warum SUBBAZSie davon ausgehen, dass Sie eine 5 statt der 4tatsächlich im Code geschriebenen übergeben haben.

Neuere Versionen von Fortran verringern dieses Problem, indem Sie INTENTeine Variable als INoder deklarieren OUTund einen Fehler (oder zumindest eine Warnung) ausgeben, wenn Sie eine Konstante als OUTParameter übergeben.

dan04
quelle
5

Wenn eine Konstante in FORTRAN an eine andere Prozedur übergeben wird, ist sie nicht mehr geschützt. Darauf beziehen sie sich. Andere beliebte Programmiersprachen in der gleichen Zeit waren C und Pascal, die dieses Problem nicht hatten (und immer noch nicht hatten). Vielleicht gibt es ältere Programmiersprachen, von denen ich nicht weiß, dass sie dasselbe Problem haben.

dj bazzie wazzie
quelle
Es bezieht sich auch auf die Tatsache, dass sich der konstante Pool nicht in einem schreibgeschützten Segment befand. Wenn dies der Fall ist und 4 als Referenz übergeben und vom Angerufenen geändert wird, würde die SEGV ohne erfolgreiche Änderung von 4 durchgeführt.
Basile Starynkevitch
Das liegt daran, dass nicht jedes Betriebssystem ein Nur-Lese-Segment hatte. Die Gefahr könnte beispielsweise unter DOS bestehen, wenn Betriebssysteme mit schreibgeschützten Segmenten (die virtuellen Speicher verwenden) wie UNIX zur Laufzeit einen Segmentierungsfehler ausgeben. Auf jeden Fall sollte der Compiler dies nicht zulassen.
DJ Bazzie Wazzie
4
Ich vermisse Pascal :(
Gareth
1
Genauer gesagt wird FORTRAN als Referenz übergeben. Wenn Sie also eine Konstante als Funktionsparameter übergeben, können Sie diesen Wert für jede Verwendung dieser Zahl ändern.
Gabe
1
Nur wenn diese Konstante (als Referenz übergeben) in einem Lese- / Schreibsegment verbleibt. Wenn es sich in einem .rodataschreibgeschützten Segment befindet (wie es aktuelle Compiler tun), ändert es die Konstante nicht, würde aber eine SEGV verursachen.
Basile Starynkevitch