Знаменитые баги и их последствия
Согласно классическому определению, в программировании баг — это ошибка в программе или системе, из-за которой она ведёт себя не так, как ожидалось. Иногда последствия ограничиваются раздражающим сбоем на экране. Иногда — потерянными деньгами, сорванным запуском ракеты, остановленным кораблём или человеческими жертвами. История технологий убедительно показывает: в сложных системах даже крошечная неточность может стать началом большой катастрофы.
Само слово bug появилось в технической среде задолго до современных компьютеров. Одно из ранних употреблений обычно связывают с Томасом Эдисоном. В конце XIX века он использовал это слово для обозначения мелких технических неисправностей, которые мешали изобретению работать так, как задумано. В письме 1878 года Эдисон писал, что после первой вспышки интуиции почти всегда начинаются трудности: устройство отказывается работать, проявляются “bugs” — мелкие ошибки и препятствия, — и требуются месяцы наблюдений, исследований и усилий, прежде чем изобретение удаётся довести до коммерческого успеха или признать неудачным.
Любопытно, что слово debugging, которое сегодня означает отладку программы и поиск ошибок, употреблялось ещё до эпохи массового программирования. В середине XX века его можно было встретить применительно не к программам, а к техническим системам, в том числе авиационным двигателям.
С компьютерами история слова bug стала особенно знаменитой благодаря Грейс Хоппер и вычислительной машине Harvard Mark II. В 1947 году инженеры обнаружили, что сбой в работе машины вызвал самый настоящий мотылёк, застрявший в электромеханическом реле. Насекомое аккуратно извлекли и приклеили к странице рабочего журнала. Подпись гласила: “First actual case of bug being found” — первый реальный случай обнаружения бага. Важно понимать: это не было первым употреблением слова bug в техническом смысле. Но это был настолько яркий и буквальный эпизод, что он навсегда вошёл в культуру программирования.
В наш век настоящие насекомые уже вряд ли смогут сломать программу. Зато их цифровые родственники каждый год доставляют людям огромные проблемы. История знает множество случаев, когда одна строка кода, одна неверная переменная или один забытый символ приводили к последствиям, несоизмеримым с размером самой ошибки.
Сломать за 60 секунд
В 2016 году владельцы техники Apple случайно выяснили: если на некоторых iPhone или iPad вручную установить дату 1 января 1970 года, а затем перезагрузить устройство, оно может превратиться в “кирпич”. На экране застывал логотип Apple, а устройство больше не загружалось обычным способом. В интернете быстро появились “шутки” о секретной пасхалке, ретро-логотипе Apple или возможности бесплатно получить платные приложения. Итог был один: вместо смартфона пользователь получал серьёзную проблему.
Ошибка затрагивала 64-битные устройства Apple на базе процессоров A7 и новее. Причина была связана с Unix-временем: в Unix-подобных системах точкой отсчёта считается 1 января 1970 года, а время хранится как количество секунд, прошедших с этого момента. Для человека такая система выглядит непривычно, но для компьютера она удобна и логична. Проблемы начинаются тогда, когда программная логика не учитывает граничные значения. Если система неожиданно получает нулевое или близкое к нулю значение времени, а затем пытается выполнить с ним дополнительные вычисления, результат может оказаться разрушительным.
Apple позднее подготовила исправления, но сам случай стал хорошим напоминанием: даже дата в настройках может оказаться не просто декоративной цифрой, а частью глубокой системной логики.
Похожие ошибки хорошо знакомы разработчикам старых игр и программ. Во времена MS-DOS нередко встречались сбои из-за переполнения счётчика. Например, в популярной легенде о Civilization миролюбивый Ганди якобы становился сверхагрессивным из-за того, что значение агрессии уходило ниже нуля и превращалось в максимальное. Историчность именно этой игровой истории спорна, но сам тип ошибки абсолютно реален: если переменная допускает значения только от 0 до 255, попытка вычесть единицу из нуля может привести к неожиданному результату. В других играх и программах подобные ошибки действительно могли превращать максимальные характеристики в нулевые, ломать баланс или полностью сбивать работу системы.
Есть и более серьёзная дата, о которой программисты помнят до сих пор: 19 января 2038 года. В этот момент в системах, использующих 32-битное signed integer для хранения Unix-времени, значение секунд превысит максимально допустимое число. Многие современные системы уже давно адаптированы к этой проблеме, но старое встроенное оборудование, промышленные контроллеры и забытые legacy-системы всё ещё могут оказаться уязвимыми.
Самая дорогая черта в истории
Mariner 1 был космическим аппаратом NASA, созданным для изучения Венеры. Его запуск состоялся 22 июля 1962 года, но уже через несколько минут после старта ракета была уничтожена по команде с Земли.
Проблемы начались вскоре после запуска. Ракета стала отклоняться от безопасной траектории, и специалисты приняли решение уничтожить её, чтобы избежать ещё более опасных последствий. Долгое время в популярной культуре этот случай называли историей о “самом дорогом дефисе”. Однако это не совсем точно.
Суть ошибки заключалась не в обычном дефисе, а в пропущенном надчеркивании — overbar — в математической записи, использовавшейся при переносе формул в программную логику. Из-за отсутствия этого символа система наведения неверно интерпретировала данные и стала реагировать на отклонения не так, как должна была. В результате ракета получила неправильные команды коррекции курса. Одна маленькая черта в формуле оказалась достаточно важной, чтобы сорвать миссию.
Метод копипаста
Ariane 5 — европейская ракета-носитель, разработанная для выведения полезной нагрузки на орбиту. Первый запуск Ariane 5 состоялся 4 июня 1996 года и закончился одной из самых известных аварий в истории программного обеспечения.
Через несколько десятков секунд после старта ракета отклонилась от расчётной траектории и была уничтожена. Вместе с ней были потеряны научные спутники стоимостью в сотни миллионов долларов.
Суть бага заключалась в том, что часть программного обеспечения была унаследована от Ariane 4. Для предыдущей ракеты эта логика была допустимой, но Ariane 5 имела другие динамические характеристики и другой профиль полёта. В определённый момент значение, связанное с движением ракеты, оказалось слишком большим для преобразования из 64-битного floating-point формата в 16-битное signed integer. Возникло исключение, инерциальная навигационная система вышла из строя, резервная система повторила ту же ошибку, и ракета потеряла управление.
Этот случай стал классическим примером опасности бездумного повторного использования кода. Сам по себе copy-paste не является злом. Но код, написанный для одной системы, может стать смертельно опасным в другой, если не проверить, какие предположения в него заложены.
Защита от дурака
В сентябре 1997 года ракетный крейсер USS Yorktown на несколько часов оказался “dead in the water” — фактически без хода — из-за сбоя в компьютерной системе управления. К счастью, это произошло во время манёвров, а не в боевой ситуации.
Корабль был частью программы Smart Ship и использовал сеть компьютеров на Windows NT, соединённых высокоскоростными линиями связи. Такая автоматизация должна была сократить численность экипажа и снизить расходы. Всё работало до тех пор, пока в систему не попало некорректное значение.
Суть бага была банальной и одновременно показательной: в одно из полей был введён ноль, после чего программа попыталась выполнить деление на ноль. Любой школьник знает, что делить на ноль нельзя, но компьютер не “знает” ничего сам по себе. Он выполняет инструкции. Если программист не предусмотрел проверку входных данных и обработку исключений, система может не просто выдать ошибку, а потянуть за собой другие компоненты. Именно это и произошло: сбой распространился по сети и вывел из строя важные элементы управления.
Этот случай часто приводят как пример того, почему критические системы должны проектироваться не только на нормальную работу, но и на ошибки оператора, плохие данные и непредвиденные сценарии.
Одна треть секунды
Не все программные ошибки заканчиваются без жертв. Один из самых трагических случаев произошёл в 1991 году во время войны в Персидском заливе. Американская система Patriot не смогла перехватить иракскую ракету Scud, которая ударила по казарме в Дахране, Саудовская Аравия. Погибли 28 американских военнослужащих.
Суть бага была связана с накоплением ошибки при вычислении времени. Система Patriot хранила время в десятых долях секунды, но из-за особенностей представления дробных чисел в двоичной системе возникала небольшая неточность. Пока система работала недолго, ошибка была незначительной. Но после длительной непрерывной работы она накопилась примерно до трети секунды.
Для обычного человека треть секунды — почти ничто. Для противоракетной системы это огромная величина. За это время ракета успевает пройти сотни метров. Компьютер обнаружил цель, но из-за ошибки во времени неверно рассчитал её положение и решил, что ракеты уже нет там, где её следовало перехватывать. Попытка перехвата была отменена.
Эта история особенно страшна тем, что ошибка была математически маленькой, но практически смертельной. В мире высоких скоростей, оружия и автоматизированных решений даже доли секунды имеют цену.
Когда машины начинают продавать друг другу
Чёрный понедельник — 19 октября 1987 года — стал днём одного из самых резких падений американского фондового рынка. Индекс Dow Jones Industrial Average упал более чем на 20% за один день. Обвал затронул рынки по всему миру и надолго стал символом того, как быстро финансовая система может войти в режим паники.
Называть этот случай простым “багом” было бы неточно. Причин у обвала было несколько: переоценённый рынок, рост процентных ставок, макроэкономические страхи, напряжение в мировой финансовой системе и слабость рыночной инфраструктуры того времени. Но программная торговля и стратегии portfolio insurance действительно сыграли важную роль в усилении падения.
Суть проблемы заключалась в том, что многие крупные участники рынка использовали автоматизированные стратегии, которые должны были защищать портфели от убытков. Когда рынок начал снижаться, эти системы стали продавать фьючерсы и акции, чтобы уменьшить риск. Но поскольку похожие алгоритмы срабатывали у многих игроков одновременно, продажи усиливали падение, падение запускало новые продажи, и рынок вошёл в цепную реакцию.
С финансовой точки зрения Чёрный понедельник не стал концом мировой экономики. Но психологически это был момент, когда стало ясно: компьютерные системы на рынке уже не просто помогают человеку. В определённых условиях они могут ускорять его страхи, усиливать толпу и создавать динамику, которую сами люди уже не успевают остановить.
Именно поэтому разговор о багах — это не только разговор о программистах. Это разговор о нашей зависимости от невидимых систем. Сегодня код управляет банками, самолётами, автомобилями, больницами, биржами, телефонами, электросетями и военной техникой. Ошибка может быть крошечной. Последствия — огромными.
