В 1989 году Феликс Ли, Джон Хейс и Анджела Томас написали тест Хакера, приняв форму викторины со многими инсайдерскими шутками: « Ты ешь слизь? »
Я рассматриваю следующие серии:
0015 Ever change the value of 4?
0016 ... Unintentionally?
0017 ... In a language other than Fortran?
Есть ли конкретный анекдот, делающий цифру «4» определенной в серии?
Позволяет ли какая-то реализация на Фортране изменять значение констант? Было ли это возможно на других языках общего пользования в то время?
4
на5
в интернированных списки целых чисел.4 = 5
было возможноОтветы:
В старые времена (1970-е и ранее) на некоторых компьютерах не было MMU (и это верно сегодня для очень дешевых микроконтроллеров).
В таких системах нет защиты памяти, поэтому в адресном пространстве нет сегмента, доступного только для чтения , и глючная программа может перезаписать константу (либо в памяти данных, либо даже внутри машинного кода).
Компиляторы Фортрана в то время передавали формальные аргументы по ссылке . Так что, если вы это сделали,
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 ++.
Кстати: быть придирчивым: перезапись 4 - это не вопрос языка, а реализация.
источник
gfortran
. Константы помещаются в их сегмент и передаются по ссылке на подпрограмму. По умолчанию постоянная секция доступна только для чтения, поэтому ошибка защиты памяти убивает программу.Это было непреднамеренным побочным эффектом стратегии оценки вызовов функций FORTRAN в сочетании с ошибочной оптимизацией компилятора.
FORTRAN II представил пользовательские функции и подпрограммы с аргументами, передаваемыми по ссылке . (Почему, я не знаю. Вероятно, это было более эффективно, чем передача по стоимости на оборудовании IBM того времени.)
Обычно передача по ссылке означает, что вы должны передать значение l (например, переменную) вместо значения r. Но дизайнеры FORTRAN решили быть полезными и в любом случае позволили вам передать r-значения в качестве аргументов. Компилятор автоматически сгенерирует для вас переменную. Итак, если вы написали:
компилятор преобразует это за кулисами в нечто вроде
Была также общая оптимизация компилятора, называемая «литеральный пул», которая объединяла бы несколько экземпляров одной и той же числовой константы в одну автоматически сгенерированную переменную. (Несколько языков в семействе C требуют этого для строковых литералов.) Итак, если вы написали
это будет рассматриваться как если бы это было
что кажется вполне разумным, пока у вас не появится подпрограмма, которая изменяет значение ее параметров.
Boom!
CALL SUBBAR(4)
изменил значение 4 в литеральном пуле на 5. И тогда вам остается только удивляться, почемуSUBBAZ
вы предполагаете, что вы передали ему 5 вместо того, что4
вы фактически написали в коде.Более новые версии Fortran смягчают эту проблему, позволяя вам объявить
INTENT
переменную какIN
или илиOUT
выдавая ошибку (или, по крайней мере, предупреждение), если вы передаете константу в качествеOUT
параметра.источник
В FORTRAN, когда константа передается другой процедуре, она больше не защищена. Вот на что они ссылаются. Другими популярными языками программирования в то время были C и Pascal, у которых не было (и до сих пор нет) этой проблемы. Возможно, есть более старые языки программирования, о которых я не знаю, которые имеют ту же проблему.
источник
.rodata
сегменте только для чтения (как это делают текущие компиляторы), его изменение не изменит константу, а вызовет SEGV.