Сейбел:Какую самую страшную ошибку вам приходилось отлавливать?
Томпсон:В основном это были ошибки, связанные с порчей памяти. Больше такого не бывает. Не знаю почему. Но поначалу мы постоянно работали с различным экспериментальным оборудованием, и в нем были ошибки.
Сейбел:То есть память портилась из-за аппаратных ошибок, а не из-за вышедшего из-под контроля указателя?
Томпсон:Мог быть указатель. Могло быть оборудование. Или и то, и другое. Та ошибка, которая мне сейчас вспомнилась как один из худших примеров, случилась на PDP-11. Там не было блока умножения, но его можно было докупить отдельно и подключить как периферию ввода/вывода. Сохраняешь числитель и знаменатель и запускаешь. Проходит цикл ожидания, затем выдается ответ - частное и остаток. И это было сделано под PDP-11 без управления памятью, а потом к нам пришло первое экспериментальное оборудование для PDP-11 с управлением памятью, и в результате блок умножения конфликтовал с управлением памятью.
Например, сохраняем, а потом прогоняем тест занятости. А в некоторых участках теста занятости отсылался физический адрес вместо виртуального, и часть памяти в итоге затиралась числителем того, на что мы пытаемся поделить. А обнаруживалось это далеко не сразу, причем в самых разных местах. Безусловно, это самая сложная ошибка, которую мне пришлось искать.
Сейбел:Как же в итоге удалось ее отследить?
Томпсон:Я написал программу, которая должна была поставить мировой рекорд по нахождению знаков числа е. Предыдущие мировые рекорды были ограничены не вычислениями - количеством циклов в секунду, - а вводом/выводом. Я придумал новый алгоритм, узким местом которого были вычисления (ввод/вывод был тривиальным). Он был феерически тяжелым в отношении умножения и деления. И мы заметили, что машина каждый раз буквально обрушивалась, когда я запускал на ней эту свою программу. А потом и установили связь.
Сейбел:И это дало вам возможность понять, что проблема в умножителе. Вы сразу же нашли причину?
Томпсон:Сначала мы решили, что ошибка возникает, когда сохраняешь множитель в блоке умножения, потом обращаешься за ним, а его там нет. Мы обратились в компанию DEC, там ничего не нашли и не захотели связываться. Их слишком нормальным сотрудникам не хотелось иметь дело с гибридной машиной. В те дни у нас были принципиальные схемы машин, и мы, собственно, нашли ошибку по этой схеме. Потом мы позвонили в DEC и сказали им: “Соедините вот этот и вон тот проводки”.
Сейбел:К счастью, сейчас оборудование так не сыплется.
Томпсон:Да. Думаю, такие ошибки сейчас редки. К тому же сейчас компоненты гораздо более изолированы друг от друга: ошибку можно сделать, только если совсем уж безумствовать. Просто ошибиться на ассемблере: очень несложно что-то перепутать в каком-нибудь регистре при вызове подпрограммы. Но если вы имеете дело с высокоуровневым языком, где все аргументы должны подходить, такие ошибки становятся все более и более редкими.
Раньше в языках ассемблера их было множество. Если речь шла только о программах, а не о комбинации программ и оборудования, обычно они случались в одном месте и повреждалось только это место. Ошибка была с чем-то связана. Нужно было сидеть и мониторить операционную систему. И часто - или очень часто - мы видели, что случалась ошибка, как можно быстрее останавливали процесс и смотрели, что происходит в других местах, таким образом отслеживая ошибки. Их можно было так поймать.
Но вот ту, о которой я говорю, поймать было нельзя. Пока я не написал ту программу с тяжелым умножением/делением, благодаря которой стало видно, с какой частотой происходит ошибка. Вместо того чтобы падать раз в пару дней, теперь система рушилась раз в пару минут. И как только мы получили то, что обрушивает машину, у нас появился шанс это найти.
Сейбел:Сегодня некоторые говорят: “Да, конечно, у ассемблера больше всего шансов повредить память из-за программных ошибок, но и Си склонен к этому больше, чем некоторые другие языки”. Можно сделать так, что указатели будут указывать черт знает куда, и получится выход за границу массива. Вы не считаете, что это проблема?
Томпсон:Нет, ее можно обойти языковыми оборотами. Некоторые пишут хрупкий код, а некоторые - очень крепкий структурно, и тут все зависит от человека. Думаю, хрупкий код можно написать на любом языке. Я определяю хрупкий код так: допустим, требуется добавить функциональность, так вот в хорошем коде ее нужно добавить только в одно место, а в хрупком придется затронуть сразу десять мест.
Читать дальше
Конец ознакомительного отрывка
Купить книгу