Практика не устает доказывать, что в любом ПО самая главная уязвимость — человеческий фактор. И неважно, появился ли баг из-за нехватки квалифицированности специалиста, выжил после долгих часов дебага в поисках ошибки, или считался хитро замаскировавшейся фичей. Среди некоторых разработчиков даже укрепилось мнение, что баги в принципе существуют всегда и везде. Но если ошибки абстрактны и сложно воспроизводимы в реальных условиях, то проблема не является критичной.
В идеальной ситуации баги исправляют все и сразу. Но в жизни всегда есть куча задач, отодвигающих полный и бесповоротный багфикс (новый функционал, срочные хотфиксы, расставленные приоритеты при исправлении багов). Это значит, что в первую очередь находятся и исправляются очевидные и явные проблемы. Остальные тихо ждут своего часа, превращаясь в бомбы замедленного действия. Иногда ошибки приводят не только к неприятностям в жизни рядового разработчика, но и вызывают настоящие катастрофы. Сегодня у нас подборка и объяснение самых кошмарных багов в истории разработки ПО.
Знаменитый случай гибели нескольких человек, получивших смертельную дозу облучения во время сеансов радиационной терапии с применением медицинского ускорителя Therac-25. Ускорители подобного типа используют электроны для создания лучей высокой энергии, высокоточно уничтожающих опухоли.
Но некоторые пациенты получили дозы не в несколько сотен рад, как предписывало лечение, а в 20 000 рад; доза в 1000 рад для человека считается несовместимой с жизнью, причем смерть может наступить сразу после облучения.
Всего один программист создал все ПО, используемое в аппаратах Therac — а это 20 тысяч инструкций, написанных на ассемблере. И при этом во всех Therac встречался один тот же пакет библиотек, содержащий ошибки.
Ускоритель Therac-25, ставший третьим в серии успешных аппаратов лучевой терапии, мог работать с рентгеновскими лучами до 25 МэВ. Несколько лет в середине 80-х аппараты Therac-25 работали безупречно, однако со временем начали накапливаться инциденты, повлекшие за собой тяжелые последствия: от ампутации конечностей до гибели пациентов.
Первое время баги просто не замечали, а все неполадки связывали с аппаратными сбоями. Программное обеспечение, безукоризненно проработавшее тысячи часов, воспринималось идеальным и безопасным. Никаких действий для предотвращения последствий возможных ошибок не предпринималось. Кроме того, выдаваемые оператору сообщения о критических с точки зрения безопасности ситуациях выглядели как рутинные. Производитель устройств расследовал каждый инцидент, но при этом не мог воспроизвести сбой. Потребовалось несколько лет исследований сторонних экспертов, привлеченных во время суда после череды смертей, чтобы сделать вывод о наличии большой плеяды именно программных ошибок.
Так при определенной последовательности ввода команд с клавиатуры происходил некорректный вызов процедур, влекущих за собой облучение любого произвольного участка тела пациента. Отсутствие на устройстве аппаратного блокиратора критических и продолжительных доз излучения усугубляло проблему.
Одна и та же переменная в ПО Therac-25, применялась как для анализа введенных чисел, так и для определения положения поворотного круга, отвечающего за направление излучателя. Поэтому при быстром вводе команд аппарат мог принять число дозы излучения за координаты места, куда нужно направить луч — например, прямо в мозг.
Иногда Therac-25 при расчете излучения делил на ноль и соответствующим образом увеличивал величины облучения до максимально возможных. Установка булевской переменной в значение «true» производилась командой «x=x+1» из-за чего с вероятностью 1/256 при нажатии кнопки «Set» программа могла пропустить информацию о некорректном положении излучателя.
Во внутренней документации производителя было обнаружено, что одно и то же сообщение об ошибке выдавалось как в случае ненадлежащей (малой) дозы облучения, так и для большой дозировки — отличить по сообщению об ошибке одно от другого было невозможно.
Если вы разработчик или (что еще лучше) тестировщик, этот случай стоит изучить досконально — есть хорошая статья в wiki, с нее можно начать, а затем ознакомьтесь с большой статьей девятнадцатилетней давности «Мифы о безопасном ПО: уроки знаменитых катастроф». История вобрала в себя большинство классических проблем тестирования.
Как ни печально, но проблемы Therac-25 не остались уникальными. В 2000 году серию аварий вызвал другой софт, точно так же просчитывающий нужную дозу облучения для пациентов, проходящих курс лучевой терапии.
Программное обеспечение Multidata позволяло медицинскому работнику рисовать на экране компьютера порядок размещения металлических блоков, предназначенных для защиты здоровых тканей от радиации. Но софт разрешал использовать только четыре защитных блока, в то время как врачи, в целях повышения безопасности, хотели использовать все пять.
Врачи воспользовались «лайфхаком». Оказалось, что в программе не предусмотрена защита от ввода некорректных данных — можно было нарисовать все пять блоков как один большой блок с отверстием в середине. В медицинском центре онкологии Панамы не понимали, что софт Multidata устанавливал разные показатели конфигурации в зависимости от того, как размещено отверстие: от направления его размещения рассчитывалась правильная доза облучения.
Рис. 1
Из-за неверно введенных данных умерли восемь пациентов, в то время как еще 20 получили передозировку, повлекшую серьезные проблемы со здоровьем.
Рис. 2
Маленькая ошибка в программном обеспечении системы мониторинга работы оборудования General Electric Energy привела к тому, что 55 миллионов человек остались без электричества. На Восточном побережье США оказались обесточены жилые дома, школы, больницы, аэропорты.
14 августа 2003 года в 0:15 ночи оператор энергетической системы в Индиане с помощью инструмента мониторинга работы оборудования заметил небольшую проблему. Проблема вызвала раздражающий сигнал об ошибке, который оператор выключил. Оператору удалось за несколько минут решить все трудности, но он забыл перезапустить мониторинг — аварийный сигнал остался в выключенном положении.
Отключение сигнала не стало основной причиной блэкаута. Но когда через несколько часов из-за контакта с деревом вырубились провисшие линии электропередачи в Огайо — об этом никто не узнал. Проблема приняла лавинообразный характер, перегруженные линии передачи и электростанции начали вырубаться в Онтарио, Нью-Йорке, Нью-Джерси, Мичигане и далее.
Ни один из операторов не заметил каскад ошибок, которые медленно убивали энергосистему, из-за единственного выключенного сигнала тревоги — никаких дублирующих систем на этот случай не предполагалось.
Рис. 3
В 1998 году NASA потеряло спутник «Mars Climate Orbiter» стоимостью $ 125 млн из-за того, что субподрядчик, работавший над инженерными задачами, не перевел английские единицы измерения (фунты) в метрическую систему. В результате ошибки спутник после 286-дневного путешествия на большой скорости вошел в марсианскую атмосферу, где из-за возникших перегрузок его системы связи вышли из строя. Аппарат оказался на сто километров ниже планируемой орбиты и на 25 км ниже высоты, на которой еще можно было исправить ситуацию. В результате спутник разбился. Такая же участь постигла космический аппарат Mars Polar Lander.
Рис. 4
В 1962 году космический корабль «Mariner 1» был уничтожен с земли после старта из-за отклонения от курса. Авария возникла на ракете из-за программного обеспечения, в котором разработчик пропустил всего один символ. В результате корабль стоимостью 18 миллионов долларов (в деньгах тех лет) получал неверные управляющие сигналы.
При работе над системой управления ракетой программист переводил рукописные математические формулы в компьютерный код. Символ «верхнего тире» (индекса), он воспринял за обычное тире (или знак минус). Функция сглаживания стала отражать нормальные вариации скорости ракеты как критические и недопустимые.
Однако даже допущенная ошибка могла не привести к критическому сбою, но как назло антенна ракеты потеряла связь с наводящей системой на Земле, и управление взял на себя бортовой компьютер.
Рис. 5
26 сентября 1983 года спутник эшелона «Око» системы предупреждения о ракетном нападении СССР ошибочно сообщил о запуске пяти баллистических ракет с территории США. Спутник находился на высокой эллиптической орбите, наблюдая за районами базирования ракет под таким углом, чтобы они находились на краю видимого диска Земли. Это позволяло обнаружить факт запуска на фоне темного космического пространства по инфракрасному излучению работающего ракетного двигателя. Кроме того, выбранное расположение спутника снижало вероятность засветок датчиков отраженным от облаков или снега солнечным светом.
После безупречного года работы внезапно выяснилось, что в один день при определенном положении спутника и Солнца свет отражается от облаков, расположенных на больших высотах, оставляя то самое инфракрасное излучение, которое компьютеры восприняли как след от ракет. Заступивший на боевое дежурство подполковник Станислав Петров усомнился в показаниях системы. Подозрение вызвало сообщение о пяти замеченных целях — в случае реального военного конфликта США одновременно произвели бы сотни пусков. Подполковник Петров решил, что это ложное срабатывание системы, и тем самым, вероятно, предотвратил Третью мировую войну.
Подобная ошибка, едва не повлекшая за собой глобальный ядерный конфликт, произошла и по другую сторону океана. 9 ноября 1979 года из-за сбоя компьютера воздушно-космической обороны Северной Америки была получена информация о начале ракетной атаки против США — в количестве 2200 запусков. В то же время спутники раннего предупреждения и радары показали, что никакой информации о советской атаке не поступало — только благодаря перепроверке данных, сделанной за 10 минут, не был отдан приказ о взаимном гарантированном уничтожении.
Причиной всему оказалась самая опасная уязвимость — человеческий фактор. Оператор компьютера, находящегося на боевом дежурстве, загрузил в него пленку с учебной программой, имитировавшей ситуацию массированной ракетной атаки.
За несколько первых лет работы Национального центра управления Объединенного командования аэрокосмической обороны США и Канады было зафиксировано 3703 ложных сигнала тревоги, большая часть из которых появилась из-за атмосферных явлений. Однако случались и компьютерные ошибки. Так один из «боевых» компьютеров 3 июня 1980 года показал постоянно меняющиеся цифры количества ракет, запущенных Советским Союзом. Проблема возникла из-за аппаратного сбоя в микросхеме.
Рис. 5
В 1997 американский ракетный крейсер «Йорктаун» (CG-48), на котором были установлены 27 компьютеров (Pentium-Pro на 200 МГц), решил поделить на ноль и полностью вышел из строя. Компьютеры работали на Windows NT — и работали они ровно так, как вы и ожидаете, узнав название оси. В то время ВМФ США старался максимально широко использовать коммерческое ПО с целью снижения стоимости военной техники. Компьютеры же позволяли автоматизировать управление кораблем без участия человека.
На компьютеры «Йорктауна» поставили новую программу, управляющую двигателями. Один из операторов, занимавшийся калибровкой клапанов топливной системы, записал в одну из ячеек расчетной таблицы нулевое значение. 21 сентября 1997 года программа запустила операцию деления на этот самый ноль, началась цепная реакция, и ошибка быстро перекинулась на другие компьютеры локальной сети. В результате отказала вся компьютерная система «Йорктауна». Потребовалось почти три часа, чтобы подключить аварийную систему управления.
Схожая проблема с нулем возникла при испытании истребителя в Израиле. Безупречно работавший самолет на автопилоте пролетел над равнинной частью, над горной частью, над долиной реки Иордан и приблизился к Мертвому морю. В этот момент произошел сбой, автопилот выключился, и пилоты посадили истребитель на ручном управлении.
После долгих разбирательств удалось выяснить, что программы автопилота при вычислении параметров управления производили деление на значение текущей высоты истребителя над уровнем океана. Соответственно, у Мертвого моря, лежащего ниже уровня океана, высота становилась нулевой, провоцируя ошибку.
Рис. 6
В мире найдется немало историй, когда обновление софта, совершаемое с самыми благими целями, могло повести за собой множество проблем. В 2008 году атомная электростанция в штате Джорджия (США) мощностью 1,759 МВт в экстренном режиме приостановила работу на 48 часов.
Инженер компании, занимающейся технологическим обслуживанием станции, установил обновление на главный компьютер сети АЭС. Компьютер использовался для слежения за химическими данными и диагностики одной из основных систем электростанции. После установки обновлений компьютер штатно перезагрузился, стерев из памяти данные управляющих систем. Система безопасности станции восприняла потерю части данных как выброс радиоактивных веществ в системы охлаждения реактора. В результате автоматика подала сигнал тревоги и остановила все процессы на станции.
Рис. 6
Двенадцать F-22 Raptor (истребитель пятого поколения, состоящий на вооружении США), стоимостью $ 140 млн за штуку, отправились в первый международный вылет в Окинаву. Все шло замечательно, пока эскадрилья не пересекла линию перемены даты, на западной стороне которой дата сдвинута на один день вперед относительно восточной. После пересечения условной линии все 12 истребителей одновременно выдали сообщение об ошибке, эквивалентной синему экрану смерти.
Самолеты потеряли доступ к данным о количестве топлива, датчикам скорости и высоты, частично нарушилась связь. В течение нескольких часов самые современные истребители Америки летели через океан совершенно беспомощными. В конце концов их удалось посадить только благодаря мастерству пилотов.
Так в чем же была ошибка? Проектировщики из Lockheed Martin даже не рассматривали вопрос о возможности пересечения линии перемены дат — им просто не пришло в голову, что где-то понадобится либо прибавлять, либо вычитать одни сутки.
В этой бескрайней теме есть еще несколько интересных историй. О них сложилось либо неправильное мнение, либо уже были подробные статьи на ГТ и Хабре.
Взрыв на советской газотранспортной системе в 1982 году из-за программных ошибок, заложенных ЦРУ. Эксперты категорически отрицают не только взрыв на газопроводе «Уренгой-Сургут-Челябинск» в 1982 году, но и вообще возможность возникновения такого взрыва.
Алгоритмическая ошибка привела к аварии самолета А-330 — в результате инцидента 119 пассажиров и членов экипажа получили ранения, из них 12 тяжелые.
Ракета-носитель Ariane 5 превратилась в «конфетти» 4 июня 1996 года — ошибка произошла в компоненте ПО, предназначенном для выполнения «регулировки» инерциальной платформы. Потеряно 500 млн долларов (стоимость ракеты с грузом).
Toyota: из-за корявой электроники и софта 89 человек погибли с 2000 по 2010 годы.