"Коли-небудь змінили значення 4?" - як це ввійшло у вікторину Хейса-Томаса?


24

У 1989 році Фелікс Лі, Джон Хейс та Анжела Томас написали тест Хекера у формі вікторини з багатьма інсайдерськими жартами: " Чи їсте ви слизькі форми? "

Я розглядаю наступні серії:

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

Чи є якийсь анекдот, який робить число "4" конкретним у серії?

Чи дозволила якась реалізація Fortran змінити значення констант? Чи це було можливо в інших загальновживаних на той час мовах?


2
@Ordous Я не заперечую, якщо ми збережемо друге запитання тут, особливо якщо відповідачі дбають про те, щоб пояснити, чому така поведінка існує в сучасних мовах (тобто чи є для цього практичне використання?). Однак, це також спричинить відмінне запитання Code Golf .
янніс

8
Пов'язане: Напишіть програму, яка становить 2 + 2 = 5 . Java , і Python відповіді там замінити 4на 5в інтернованих списки цілих чисел.
Martijn Pieters

5
І коментар на цій сторінці зазначає, що ви можете переосмислити літерали у FORTRAN IV; 4 = 5було можливо.
Martijn Pieters

7
І дякую за тестове посилання Хакера. Тепер ти змусив мене почувати себе старим, а також жахнувся того, як часто я можу відповісти «так» на питання.
Martijn Pieters

5
Я змінив значення постійного нуля в програмі fortran один раз. Це був дуже важкий помилок, щоб вистежити.
Брайан Оуклі

Відповіді:


32

У старі часи (1970-ті роки і раніше) деякі комп’ютери не мали ММУ (і це актуально сьогодні для дуже дешевих мікроконтролерів).

У таких системах відсутній захист пам’яті, тому немає жодного сегмента, призначеного лише для читання, в адресному просторі , і програма-баггі може замінити константу (або в пам'яті даних, або навіть всередині машинного коду).

У той час компілятори Fortran передавали офіційні аргументи шляхом посилання . Отже, якщо ви зробили, CALL FUN(4)і SUBROUTINE FUN(I)його тіло змінюється I- наприклад, із заявою I = I + 1в його тілі, ви можете статися до катастрофи, змінивши 4 на 5 у абонента (або ще гірше).

Це було справедливо і для перших мікрокомп'ютерів, таких як оригінальний IBM PC AT 1984 року, з MS-DOS

FWIW, я досить старий, щоб використовував, як підліток-аггер на початку 1970-х, такі комп'ютери: IBM1620 та CAB500 (в музеї: це комп’ютери епохи 1960-х років!). IBM1620 був досить веселим: він використовувався в таблицях пам'яті для додавання та множення (і якщо ви перезаписали ці таблиці, настав хаос). Таким чином, ви не тільки можете перезаписати 4, але навіть можете перезаписати кожне майбутнє додавання 2 + 2 або множення 7 * 8 (але я дійсно забув ці брудні деталі, щоб вони могли бути неправильними).

Сьогодні ви можете перезаписати код BIOS у флеш-пам'ять, якщо ви будете достатньо наполегливі. На жаль, я вже не відчуваю такої забави, тому ніколи не пробував. (Я навіть боюся встановлювати деякі LinuxBios на своїй материнській платі).

На сучасних комп'ютерах та операційних системах передача константи за допомогою посилання та зміна її всередині виклику просто спровокує порушення сегментації , що звучить звично багатьом розробникам C або C ++.

BTW: бути запозиченим: перезапис 4 - це не мова, а реалізація.


14
1620 рік отримав прізвисько CADET: Не можу додавати, навіть не намагатися.
Піт Бекер

Трюк можна майже повторити навіть зараз gfortran. Константи розміщуються в їх сегменті і передаються посиланням на підпрограму. За замовчуванням постійний розділ є лише для читання, тому помилка захисту пам’яті вбиває програму.
Netch

7

Це був ненавмисний побічний ефект стратегії оцінювання викликів функції FORTRAN у поєднанні з помилковою оптимізацією компілятора.

FORTRAN II представив визначені користувачем функції та підпрограми зі своїми аргументами, переданими посиланням . (Чому я не знаю. Це, мабуть, було більш ефективно, ніж прохідна вартість на апаратному забезпеченні IBM того часу.)

Зазвичай передача посилань означає, що вам доведеться передавати l-значення (як змінну) замість r-значення. Але дизайнери FORTRAN вирішили бути корисними і дозволяють вам передавати r-значення як аргументи в будь-якому випадку. Компілятор автоматично генерує змінну для вас. Отже, якщо ви написали:

CALL SUBFOO(X + Y, 4)

компілятор перетворив би це за кадром у щось подібне

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

Існувала також загальна оптимізація компілятора, що називається "буквальний пул", яка об'єднала б декілька екземплярів однієї чисельної константи в одну і ту ж автоматично сгенеровану змінну. (Декілька мов сімейства C вимагають цього для рядкових літералів.) Отже, якщо ви писали

CALL SUBBAR(4)
CALL SUBBAZ(4)

це трактується так, як ніби

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

що видається цілком розумною справою, поки у вас не з’явиться підпрограма, яка змінює значення її параметрів.

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

Бум! CALL SUBBAR(4)змінив значення 4 у прямому пулі на 5. І тоді вам залишається цікаво, чому SUBBAZприпускаєте, що ви передали його 5 замість того, що 4ви насправді написали в коді.

Більш новіші версії Fortran пом'якшують цю проблему, дозволяючи вам оголосити INTENTзмінну як INабо OUTі подати вам помилку (або принаймні попередження), якщо ви передаєте константу як OUTпараметр.


5

У FORTRAN, коли константа передається іншій процедурі, вона більше не захищена. Саме так вони і посилаються. Іншими популярними мовами програмування того ж часу були C та Pascal, які не мали (і досі не мають) цієї проблеми. Можливо, є більш старі мови програмування, про які я не знаю, що мають те саме питання.


Крім того, це стосується того, що постійний пул не знаходився в сегменті, призначеному лише для читання. Якби це сталося, і 4 було передано за посиланням, а його змінили викликом, SEGV відбудеться без успішної зміни 4.
Basile Starynkevitch

Це тому, що не кожна ОС мала сегмент, доступний лише для читання. Скамінь може бути використаний, наприклад, у DOS, операційні системи з сегментами лише для читання (з використанням віртуальної пам'яті), як UNIX, повертають помилку помилки сегментації під час виконання. У всякому разі, компілятор не повинен цього допускати.
dj bazzie wazzie

4
Я сумую за Паскалем :(
Гарет

1
Щоб бути більш конкретним, FORTRAN передає посилання. Отже, якщо ви передаєте константу як параметр функції, ви можете змінити це значення для кожного використання цього числа.
Гейб

1
Тільки якщо ця константа (передана посиланням) залишається в сегменті читання-запису. Якщо він знаходиться в .rodataсегменті, призначеному лише для читання (як це роблять поточні компілятори), це не змінить константу, але призведе до SEGV.
Базиль Старинкевич
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.