На первый взгляд кажется, что катастрофы случаются из-за сложных стечений обстоятельств — масштабного отказа техники или стихии. Но иногда достаточно пропущенной черты в уравнении, лишнего нуля в поле ввода. Мы собрали истории о том, как несколько символов в коде приводили к потере космических аппаратов, обрушению телефонных сетей и гибели людей. И о том, почему программисты всего мира до сих пор учатся на этих ошибках.

Mariner 1: как пропущенная черта стоила 18,5 млн долл.
22 июля 1962 года с мыса Канаверал стартовала ракета, которая должна была открыть человечеству Венеру. На борту находился аппарат «Маринер-1» — первый американский зонд, которому предстояло совершить облет соседней планеты. В центре управления царило напряжение: миссия готовилась годами, и все зависело от того, насколько точно ракета выдержит курс в первые минуты полета. Вначале все шло штатно.
Но примерно через четыре минуты после старта произошло то, чего многие боялись: аппарат начал отклоняться от расчетной траектории. Офицер по безопасности полетов, видя, что ракета уходит в сторону, был вынужден отдать команду на подрыв. Ракета с зондом рухнула в океан. Стоимость потерянного аппарата и носителя составила 18,5 млн долл. — по тем временам колоссальная сумма.

Причина катастрофы оказалась почти анекдотичной. В навигационных уравнениях, которые вводились в компьютер, была пропущена одна деталь. Долгое время в прессе и даже в некоторых технических изданиях писали, что виной всему «пропущенный дефис». Но современные историки NASA уточняют: на самом деле речь шла не о дефисе, а о пропущенной черте над символом R, обозначавшим радиус. При ручном переносе уравнений в программу эта черта имела критическое значение — без нее компьютер неправильно интерпретировал уравнение.
Эта история стала хрестоматийной из-за урока, который она преподала инженерам. Одна незаметная деталь в математической записи — и целая миссия по исследованию другой планеты оказалась провалена. Впрочем, NASA быстро сделало выводы, и уже 27 августа 1962 года к Венере отправился «Маринер-2», который успешно выполнил свою задачу. Но «Маринер-1» навсегда остался символом того, насколько хрупким может быть программный код, даже когда за ним стоят лучшие умы своего времени.
AT&T, 1990: ошибка, обрушившая телефонную сеть Америки
В AT&T рубежа 1980-х и 1990-х годов все безоговорочно верили в надежность собственной сети. Компания была национальным символом связи, через которую проходили миллионы деловых переговоров и обычных звонков. Инженеры Bell Labs, исследовательского подразделения AT&T, в то время считались чуть ли не элитой мировой инженерии — именно здесь придумали транзистор, лазер и язык программирования C. Когда на рубеже 1989-1990 годов на коммутаторах 4ESS начали устанавливать обновление ПО, никто не сомневался, что все пройдет гладко.
15 января 1990 года для жителей США начался как обычный понедельник. Но к середине дня страна столкнулась с тем, что сегодня назвали бы «цифровым апокалипсисом». Около 50% междугородних звонков по сети AT&T не могли соединиться. Авиакомпании не могли подтвердить бронирования, банки не проводили транзакции, службы экстренной помощи работали с перебоями.
Проблема была не в перегрузке сети и не в физическом повреждении кабелей. Все дело было в обновлении, которое AT&T установила за несколько недель до инцидента для своих коммутаторов 4ESS — огромных машин, которые обрабатывали междугородний трафик по всей стране.
В новом коде содержалась ошибка, связанная с обработкой сигналов, которые передаются по отдельному каналу и не слышны абонентам. Когда один из коммутаторов сталкивался с определенной комбинацией сигналов, он аварийно перезагружался. Но самое страшное начиналось дальше: соседние коммутаторы, получая сигнал о сбое, тоже начинали перезагружаться. Возникала цепная реакция, которая за считанные минуты охватила всю сеть.
Инженеры Bell Labs несколько часов пытались восстановить связь. Причина сбоя оказалась в небольшой ошибке в программном коде. Оператор «break», который должен был завершать выполнение определенной команды, оказался расположен в коде не там, где нужно. Из-за этого программа неправильно обрабатывала сигналы от других коммутаторов. Когда один из них перезагружался, соседние устройства воспринимали поступивший сигнал как повод для собственного перезапуска. Так сбой распространялся по сети, словно эффект домино.
После этого случая стало ясно: даже гигантская корпорация с лучшими инженерами мира может парализовать всю страну из-за одной строки кода.
USS Yorktown: как деление на ноль остановило военный корабль
В середине 1990-х годов военно-морские силы США запустили амбициозную программу Smart Ship — попытку превратить боевые корабли в полностью автоматизированные платформы, управляемые коммерческими компьютерами. Идея казалась прорывной, ведь вместо десятков специалистов, вручную следящих за двигателями и навигацией, всем должна была управлять единая цифровая система на базе Windows NT.
Первым кораблем, на который установили эту систему, стал ракетный крейсер USS Yorktown. Военные гордились проектом и планировали распространить технологию на весь флот. Крейсер, способный нести ядерное оружие и развивать скорость до 30 узлов, должен был доказать, что будущее — за автоматизацией.

Но в сентябре 1997 года, во время учений у берегов Вирджинии, эта уверенность пошатнулась. Один из членов экипажа случайно ввел в поле базы данных ноль, на который система попыталась разделить число, после чего произошел сбой.
Само по себе деление на ноль — тривиальная ошибка, с которой сталкивается любой начинающий программист. Но на Yorktown эта ошибка привела к каскадному отказу: приложение рухнуло, операционная система Windows NT не смогла корректно обработать исключение и зависла, а вместе с ней остановились все консоли на корабле. Управление двигателями было потеряно. Крейсер, способный нести ядерное оружие, оказался «мертвым в воде» на несколько часов.
Этот случай стал символом другого класса проблем: когда в критически важных системах используется коммерческое программное обеспечение, не предназначенное для работы в условиях, где ошибка может стоить жизней. История с делением на ноль вошла в учебники по надежности программного обеспечения как пример того, что даже самые простые ошибки могут иметь самые серьезные последствия, если система не предусматривает защиту от них.
Ariane 5: тридцать секунд и переполнение, которое никто не предусмотрел
К середине 1990-х годов Европейское космическое агентство оказалось в сложном положении: его основная ракета Ariane 4 морально устарела, а американские и российские конкуренты предлагали все более выгодные условия запуска. Нужна была новая тяжелая ракета, способная выводить на орбиту сразу два крупных спутника.
На разработку проекта Ariane 5 ушли годы, многомиллиардные затраты и труд сотен инженеров. Все было рассчитано до мелочей, а программное обеспечение для системы наведения взяли от проверенной Ariane 4 — зачем изобретать заново то, что уже доказало свою надежность?
4 июня 1996 года ракета-носитель Ariane 5 стартовала с космодрома Куру во Французской Гвиане. Это был первый полет новой тяжелой ракеты, на которую возлагали огромные надежды. Но через 30 секунд после старта ракета начала отклоняться от курса, а еще через несколько секунд разрушилась и взорвалась. Обломки упали в саванну рядом с космодромом. Стоимость потерянной полезной нагрузки и самой ракеты оценивалась в сотни миллионов долларов.

Причина катастрофы оказалась в программном обеспечении, которое перешло к Ariane 5 «по наследству» от предыдущей модели, Ariane 4. Программа пыталась преобразовать 64-битное число с плавающей запятой в 16-битное целое число со знаком. На Ariane 4 эти значения всегда были небольшими, и преобразование проходило без проблем. Но Ariane 5 имела другую траекторию и развивала гораздо большую скорость. Число не поместилось в 16 бит — произошло переполнение. Обе инерциальные системы последовательно отказали, а бортовой компьютер принял диагностическую информацию за реальные данные о положении ракеты. Получив ошибочные команды, двигатели резко изменили направление тяги, что привело к разрушению ракеты.
Этот случай служит примером опасности повторного использования кода без анализа контекста. Инженеры взяли проверенную и надежную программу от Ariane 4, но не учли, что новая ракета будет работать в других условиях. В отчете комиссии позже отмечалось, что катастрофы можно было избежать, если бы в коде была предусмотрена защита от переполнения или если бы преобразование типа данных не выполнялось для величин, которые заведомо могут быть большими. Ariane 5 стала одним из самых дорогих уроков в истории программной инженерии и одним из самых наглядных примеров того, почему тестирование и анализ граничных условий важнее, чем кажется.
Patriot: ошибка округления, которая стоила 28 жизней
В феврале 1991 года, во время войны в Персидском заливе, американская батарея зенитных ракет Patriot в Дахране в Саудовской Аравии несла круглосуточное дежурство. Система, созданная для перехвата иракских ракет «Скад», работала без остановки более ста часов. На первый взгляд, все было в порядке: радар вращался, компьютеры считали, операторы дежурили. Но то, что происходило внутри процессора, не было видно никому, и именно это делало ситуацию по-настоящему опасной.
25 февраля 1991 года батарея не смогла перехватить иракскую ракету «Скад». Ракета попала в казарму, где находились американские военнослужащие. Погибли 28 человек, около ста получили ранения. Это был один из самых трагических инцидентов войны, и его причиной стала ошибка в программном обеспечении, связанная с округлением чисел с плавающей запятой.
Система Patriot отслеживала время с момента включения, используя счетчик с фиксированной точностью. Внутреннее время учитывалось в целых десятых долях секунды — для преобразования этого значения в секунды использовалось умножение на приближенное двоичное представление числа 0,1. Из-за ограниченной разрядности результат преобразования становился все менее точным, и при каждом прибавлении накапливалась крошечная ошибка. За несколько часов работы она была ничтожной, но батарея в Дахране работала непрерывно более 100 часов. Накопленная ошибка составила около 0,34 секунды — этого оказалось достаточно, чтобы радар искал «Скад» не в той точке неба, где он находился на самом деле.
Но самая драматичная деталь заключается в том, что американские военные узнали от израильских специалистов о снижении точности Patriot еще за две недели до трагедии. Исправление подготовили, но обновленное программное обеспечение поступило в Дахран только 26 февраля 1991 года — на следующий день после гибели военнослужащих.
Эта история — одна из самых горьких в нашем списке, потому что она показывает: программные ошибки могут не просто стоить денег или ломать технику, но и приводить к человеческим жертвам. Она напоминает о том, что математическая точность в программировании, а также скорость устранения выявленных проблем в критически важных системах — это вопрос жизни и смерти.
Вместо вывода
Все эти истории объединяет одно: ошибки были маленькими. Пропущенная черта, лишний символ, необработанное деление на ноль, число, не поместившееся в переменную, накопленная погрешность округления. Ни одна из них не была результатом злого умысла или грубой халатности. Это были ошибки, которые мог допустить любой программист, и которые, тем не менее, приводили к катастрофам.
По этой причине истории о багах так важны. Они напоминают, что программирование — это больше, чем просто написание кода. Это создание систем, которые взаимодействуют с реальным миром. Современные методы разработки, такие как тестирование, статический анализ, формальная верификация, код-ревью, появились во многом благодаря таким вот урокам. И хотя полностью избежать ошибок невозможно, помнить о них — значит делать следующий код чуть надежнее.
Читайте также:
Гуманоиды наконец-то пришли в квартиры, но с одним неловким нюансом.
Начало эпохи космических дата-центров: как и зачем Google отправил чип TPU на орбиту.
Как человек, который изобрел интернет, мог бы владеть им, но отдал его миру бесплатно.