Рассказывать начинающим инженерам истории о том, как ты когда-то серьёзно облажался – это хороший способ помочь им бороться с синдромом самозванца.
Это был, наверное, 1984-1985 год. Тогда я был 25-летним подающим надежды программистом с пятилетним стажем. Я и ещё один программист писали и поддерживали набор приложений, похожих на сегодняшний Office: электронные таблицы, текстовый процессор, база данных, плоттер и т.п. Мы настраивали всю эту систему для трёх-четырёх вертикальных рынков [бизнес-клиентов узкоспециальной направленности / прим. перев.].
Большую часть текстового процессора писал я сам. Писал я на Форте, и для различных вариантов комбинаций операционок и процессоров. Молодёжи невдомёк, но в те времена новые микрокомпьютеры со своей особой ОС и одним из нескольких вариантов процессоров выходили раз в несколько месяцев.
Форт использовал обмен блочными данными с диском. Каждый блок имел длину в 1 кб, и чтобы сохранить что-нибудь больше 1 кб, нужно было работать с мастер-блоком файла, где хранились смещения всех блоков с данными – по сути, это была пара списков, занятых и незанятых блоков.
Для инициализации этого мастер-блока его надо было заполнять нулями. Ну и понеслась. Короче говоря, я поменял приложение так, чтобы оно поддерживало файлы в два раза большего объёма, чем было до этого – и вместо 256 вхождений в мастер-блоке появилось 1024.
Каждое вхождение занимало – внимание – одно слово из 16 бит. Поэтому, если 512 слов ещё влезало в мой мастер-блок размером 1 кб, то 1024 слова требовали уже использования двух блоков.
Поэтому я поменял количество заполняемых нулями блоков, а размер буфера не поменял. А когда работаешь с незащищённой памятью, и пишешь 2048 нулей в пространстве на 1024 байта, то оставшиеся байты перезапишут всякий случайный мусор, попавшийся им в памяти.
В моём случае всяким случайным мусором оказался мастер-блок диска ОС. Да… И когда я инициализировал новый файл, что происходило каждый 1024-й раз при записи одноблочного файла, я перезаписывал мастер-блок диска, что удаляло с него все файлы.
И мы, конечно, выпустили эту версию, которая работала недель 8-9. И можете себе представить количество звонков от клиентов, которые нам пришлось получить. В итоге мы советовали всем сохранять резервные копии (что делалось, кстати, при помощи видеокассет) каждый божий день.
Я много недель потратил на то, чтобы просто извиняться по телефону, и одновременно прогонять мою программу в отладчике снова и снова. И у меня ничего не получалось. Ничего.
И вот одна женщина позвонила, и описала в красочных выражениях – а работала она в грузоперевозках, поэтому её примерами из области ненормативной лексики я теперь активно пользуюсь – что она сделала резервную копию, запустила текстовый процессор, и он сразу же очистил ей диск. Она снова загрузила резервную копию, и процессор опять сразу же затёр ей диск. Она была в бешенстве.
И, представьте, у меня целых два часа ушло на то, чтобы понять, как мне повезло. Я рассказывал эту историю своему коллеге за обедом, и тут вдруг меня осенило – стоп. Стоп. Сразу же? Каждый раз?
Я позвонил ей и пообещал все земные блага, только бы она упаковала эту кассету и отправила её нам. Я пообещал ей оплатить стоимость пересылки и отменить ежемесячные платежи за наши услуги (мой босс ни секунды не колебался: «Да, чёрт возьми, мы отменим её платежи»).
И вот, наконец, я смог воспроизвести эту ошибку. И она не обманывала. Та резервная копия, которую она сохранила, оказалась в критической точке: 1023 сохранения на момент создания. Загрузи резервную копию, сохрани файл, и диск гарантированно очистится.
Может, я и преувеличиваю, но, по-моему, я нашёл проблему тем же утром, когда мы получили плёнку. Её было так просто найти в отладчике.
Я смотрел на блок размером 2 кб, который должен был быть записан, и последний его 1 кб был заполнен каким-то мусором. Мне это показалось странным, и я начал разбираться. И, конечно, это был не мусор – это было 1024 байта мастер-блока диска, которые ОС хранила рядом с моим мастер-блоком файла.
Мне попала резервная копия «до» ядра – дампа ядра у меня не было, но она дала мне гарантированный способ дойти до этого дефекта. Если бы мне не повезло, я бы его так и не нашёл. Я бы просто не догадался, что я пишу не в свою память, а в системную.
Так что, да – ваш «мастер»-гик выпустил текстовый процессор, которые в течение восьми-девяти недель форматировал жёсткий диск клиента после каждого 1024-го сохранения. Потому что, ну я ж «умелец».
Моралей у этой истории можно найти много, но вот вам две главных для любого джуниора:
- Никогда не пишите в коде числовые константы, за исключением 0, 1 и -1.
- Не будьте так строги к самому себе. У всех ваших многомудрых сеньоров есть подобные истории, а у некоторых из них – и помногу.
Автор: Вячеслав Голованов