W 1989 r. Felix Lee, John Hayes i Angela Thomas napisali test hakera w formie quizu z wieloma dowcipami poufnymi: „ Czy jesz śluzowce? ”
Rozważam następującą serię:
0015 Ever change the value of 4?
0016 ... Unintentionally?
0017 ... In a language other than Fortran?
Czy jest jakaś anegdota, która sprawia, że liczba „4” jest szczególna w serii?
Czy niektóre implementacje Fortrana pozwoliły modyfikować wartość stałych? Czy było to możliwe w innych powszechnie używanych wówczas językach?
4
na5
wewnętrznych listach liczb całkowitych.4 = 5
było możliwe.Odpowiedzi:
W dawnych czasach (lata siedemdziesiąte i wcześniej) niektóre komputery nie miały MMU (i tak jest dzisiaj w przypadku bardzo tanich mikrokontrolerów).
W takich systemach nie ma ochrony pamięci, więc nie ma segmentu tylko do odczytu w przestrzeni adresowej , a błędny program mógłby nadpisać stałą (albo w pamięci danych, albo nawet w kodzie maszynowym).
Kompilatory Fortran w tym czasie przekazały formalne argumenty przez odwołanie . Więc jeśli to zrobiłeś,
CALL FUN(4)
aSUBROUTINE FUN(I)
jego ciało zmieniło sięI
- np. Z oświadczeniemI = I + 1
w ciele, możesz mieć katastrofę, zmieniając 4 na 5 u dzwoniącego (lub gorzej).Dotyczyło to również pierwszych mikrokomputerów, takich jak oryginalny IBM PC AT z 1984 r., Z MS-DOS
FWIW, jestem na tyle dorosły, że jako nastolatka użyłem na początku lat 70. takich komputerów: IBM1620 i CAB500 (w muzeum: są to komputery z lat 60.!). IBM1620 był całkiem zabawny: był używany w tabelach pamięci do dodawania i mnożenia (a jeśli nadpisałeś te tabele, nastąpił chaos). Więc nie tylko możesz zastąpić 4, ale możesz nawet zastąpić każde przyszłe dodanie 2 + 2 lub 7 * 8 mnożenia (ale tak naprawdę zapomniałem tych brudnych szczegółów, więc może się mylić).
Dzisiaj możesz nadpisać kod BIOS w pamięci flash, jeśli będziesz wystarczająco wytrwały. Niestety nie czuję już takiej zabawy, więc nigdy nie próbowałem. (Boję się nawet instalować trochę LinuxBios na mojej płycie głównej).
Na obecnych komputerach i systemach operacyjnych przekazywanie stałej przez odniesienie i zmienianie jej wewnątrz odbiorcy spowoduje po prostu naruszenie segmentacji , co brzmi znajomo dla wielu programistów C lub C ++.
BTW: być głupim: nadpisywanie 4 nie jest kwestią języka, ale implementacji.
źródło
gfortran
. Stałe są umieszczane w swoim segmencie i przekazywane przez odniesienie do podprogramu. Domyślnie sekcja stała jest tylko do odczytu, więc błąd ochrony pamięci zabija program.Był to niezamierzony efekt uboczny strategii oceny wywołań funkcji FORTRAN w połączeniu z błędną optymalizacją kompilatora.
FORTRAN II wprowadził zdefiniowane przez użytkownika funkcje i podprogramy, których argumenty przekazywane są przez odwołanie . (No nie wiem. Prawdopodobnie było to wtedy bardziej wydajne niż przekazywanie wartości na sprzęcie IBM.)
Zwykle przekazywanie przez odniesienie oznacza, że musisz przekazać wartość l (jak zmienna) zamiast wartości r. Ale projektanci FORTRAN postanowili być pomocni i pozwolić ci przekazać wartości r jako argumenty. Kompilator automatycznie wygeneruje dla ciebie zmienną. Więc jeśli napisałeś:
kompilator przekształciłby to za kulisami w coś podobnego
Istniała również wspólna optymalizacja kompilatora zwana „pulą literałów”, która konsolidowałaby wiele wystąpień tej samej stałej liczbowej w tej samej automatycznie generowanej zmiennej. (Kilka języków w rodzinie C wymaga tego do literałów łańcuchowych.) Więc jeśli napisałeś
byłoby to traktowane tak, jakby tak było
co wydaje się całkowicie rozsądną rzeczą, dopóki nie pojawi się podprogram, który zmienia wartość jego parametrów.
Bum!
CALL SUBBAR(4)
zmieniłem wartość 4 w literalnej puli na 5. A potem zastanawiasz się, dlaczegoSUBBAZ
zakładasz, że przekazałeś jej 5 zamiast4
faktycznie napisanej w kodzie.Nowsze wersje Fortran łagodzą ten problem, pozwalając zadeklarować
INTENT
zmienną jakoIN
lubOUT
i dając ci błąd (lub przynajmniej ostrzeżenie), jeśli przekażesz stałą jakoOUT
parametr.źródło
W FORTRAN, gdy stała jest przekazywana do innej procedury, nie jest już chroniona. Do tego się odnoszą. Inne popularne języki programowania w tym samym czasie to C i Pascal, które nie miały (i nadal nie mają) tego problemu. Być może istnieją starsze języki programowania, o których nie wiem, że mają ten sam problem.
źródło
.rodata
segmencie tylko do odczytu (jak robią to obecne kompilatory), zmiana nie zmieni stałej, ale spowoduje SEGV.