Therac 25 ошибка

В 1984 году на экраны вышел фильм «Терминатор» с Арнольдом Шварценеггером в главной роли. Персонаж стал посланником злобного искусственного интеллекта, который стремится уничтожить все живое на Земле или подчинить его своей воле. С чего все началось? Вероятно, с ошибки программистов, которые в коде не там поставили запятую и предоставили Skynet слишком много свободы.

Что подарить любимым? Топ идей в Каталоге Onlíner!

В 1984 году на экраны вышел фильм «Терминатор» с Арнольдом Шварценеггером в главной роли. Персонаж стал посланником злобного искусственного интеллекта, который стремится уничтожить все живое на Земле или подчинить его своей воле. С чего все началось? Вероятно, с ошибки программистов, которые в коде не там поставили запятую и предоставили Skynet слишком много свободы.

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

Содержание

  • Аппарат для лечения агрессивных форм рака
  • Оптимизация разработки
  • Начало «неприятностей»
  • Отрицание
  • Признать ошибку и остановить работу

Аппарат для лечения агрессивных форм рака

Лучевую терапию применяют давно и достаточно успешно, инженеры и медики совершенствуют технологии и оборудование, которое призвано помочь в борьбе со злокачественными образованиями. То и дело появляются революционные решения — сегодня они могут казаться устаревшими, но 30—40 лет назад считались прорывом.

В конце 1970-х годов канадское правительство инициировало разработку полностью компьютеризированной системы Therac-25 — аппарата лучевой терапии для лечения агрессивных форм рака, более эффективного с медицинской и экономической точки зрения, нежели предшественники Therac-6 и Therac-20.

Медицинский линейный ускоритель мог работать в двух режимах: с небольшой интенсивностью излучения и высокой (это упрощенное описание) в зависимости от того, на какой глубине в тканях находился очаг. Одним из ключевых отличий Therac-25 от Therac-20 стал переход на полностью программное управление.

Потенциальных покупателей системы именно этим и пытались заинтересовать: ведь вместо дорогостоящих сенсоров и аппаратных решений для защиты применялось сравнительно дешевое ПО. В прошлых же версиях системы для предотвращения неверных конфигураций применялись всевозможные ограничители, датчики, сенсоры и механизмы, обеспечивающие безопасность процедуры.

Оптимизация разработки

Чтобы оптимизировать разработку, создатели Therac-25 использовали старый код — написанный для предыдущих «тераков». Тот, в свою очередь, по данным ряда источников, был написан программистом-самоучкой, который не имел профильного образования. Возможно, по этой причине он не стал сопровождать код комментариями — разобраться в нюансах было непросто, а создавать программную платформу с нуля не захотели.

Поставки Therac-25 в медучреждения США и Канады начались в 1983 году, и первое время информации о сбоях не было. Системе было несложно пройти все инстанции и получить разрешения от регуляторов — в машине применялось уже существующее ПО, поэтому его пропустили без особых вопросов. В то время около 94% медицинского оборудования попадало на рынок именно таким образом, что упрощало, ускоряло и удешевляло вывод новых устройств. А как все это работало, вопрос другой.

Для проверки степени опасности и рисков выхода системы из строя применялся Fault Tree Analysis (или «анализ дерева отказов»). В процессе определялись те самые «опасные последствия», условия, которые к ним приведут, и предпринятые шаги в этой цепочке. Затем оценивался шанс возникновения ситуаций. Вновь подчеркнем — это упрощенное описание подхода.

Главное заключалось в том, что анализ решили не проводить, так как программное обеспечение «зарекомендовало себя как безопасное во время работы на Therac-6 и Therac-20». То, что Therac-25 значительно отличается от предыдущих поколений медицинских ускорителей, решили опустить. Компания-разработчик оценила шанс неправильной работы как почти несуществующий, а возможные ошибки в ПО проигнорировала.

Позже оказалось, что в ПО существовала уйма критических ошибок. Одну из них называют race condition. В случае с Therac-25 использовалась одна и та же переменная для двух команд, которые могли выполняться в произвольном порядке, что для описываемого аппарата неприемлемо.

К примеру, в одном из режимов при максимальной интенсивности излучения между пациентом и электронной пушкой должен был устанавливаться «рассеиватель», распределяющий поток. Машина же выполняла не ту последовательность, и на человека обрушивался мощнейший луч. Проверяющая система, в свою очередь, из-за неверной команды (которая, опять же, не проверялась дублирующими системами) неправильно оценивала уровень радиации и «стреляла» вновь.

Были и другие программные недочеты: некорректные операции с нулем приводили к выводу мощности излучения на максимум, а неверно описанная переменная генерировала неправильное положение поворотного диска с набором инструментов (для разных режимов работы и настройки) 1 раз из 256, что могло привести к многократно завышенному уровню облучения.

Свою роль играла работа магнитов, которые позиционировали поворотный диск с «прицелами» для разных видов терапии. Если оператор вносил корректировку в мощность и тип излучения слишком быстро, машина не успевала перевести диск. Тогда шансы получить высокую дозу составляли 50 на 50. Если принять во внимание все возможные ошибки, то окажется, что Therac-25 представлял собой чуть ли не русскую рулетку с радиацией вместо пуль.

Начало «неприятностей»

Основные «неприятности» аппарат лучевой терапии принес в период с 1985 по 1987 год шести людям (это те, о которых есть информация). Первый смертельный исход был зафиксирован в 1986 году.

Жертвой стал пациент, проходивший девятую для него процедуру облучения. Оператор, внося команду, допустила опечатку — вместо Е (электронная терапия) она указала Х (рентгеновская терапия). Заметив это, она вернулась на пункт выше и поставила верную букву. В этот момент в системе произошла ошибка — их случались десятки в день, так что «ничего странного».

Аппарат продолжил работу, а оператор, приняв уведомление за индикацию низкой дозы, повторила процесс облучения. Так как пациент находился в защищенном помещении вне поля зрения сотрудника, а предусмотренные системы связи были неисправными, оператор не знала, что человек за стеной скорчился от боли. Через некоторое время мужчина вскочил со стола и бросился к двери, пытаясь привлечь внимание человека за стеной.

Но «разряды» уже нанесли непоправимый вред: отказали левая рука, на которую пришлась доза облучения, и обе ноги, пациент потерял речь, а спустя пять месяцев умер от ряда осложнений.

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

На этот раз интерком работал и оператор услышала стоны пациента, чье лицо оказалось под ударом радиации. Спасти человека не удалось — мужчина впал в кому и умер спустя три недели после инцидента.

Третья жертва неверно написанного ПО, отсутствия тестирования и, вероятно, желания сэкономить умерла в январе 1987 года. Вновь речь шла о сбоях, ошибках в работе системы, ее перезагрузке и отчете компьютера о дозе в 7 рад, что не соответствовало действительности. Пациент жаловался на жжение в области облучения, это «как бы приняли к сведению», а спустя три месяца он умер от последствий лучевой болезни.

Отрицание

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

В июне 1985 года 61-летняя женщина проходила терапию после удаления раковой опухоли в груди. После сеанса лучевой терапии с использованием аппарата Therac-25 ее плечо и рука оказались парализованы, а грудь пришлось удалить. Канадская государственная корпорация AECL, которая выступала заказчиком ускорителей, отказалась признать вину.

«Этого не может быть, ошибки и некорректная работа Therac-25 исключены. Возникновение отека — это нормально», — примерно так говорилось в их заявлении.

Второй инцидент произошел спустя примерно месяц в другом медучреждении. На этот раз под излучателем оказалась 40-летняя пациентка. Во время сеанса машина сообщила о нулевой интенсивности излучения. Оператор ставил систему на паузу и возобновлял процедуру — аппарат был направлен в область таза. Это повторилось пять раз, потому что Therac-25 продолжал выдавать одно и то же уведомление — нулевая доза.

Прибывший по вызову техник отрапортовал: «Все в порядке, неисправностей нет». Пациентку госпитализировали, а позже она умерла — причиной стало развитие рака. Но останься она живой, женщине как минимум бы потребовалась замена тазобедренного сустава, уничтоженного ускорителем.

Третий инцидент имел место в том же 1985 году. Пациентка получила шрамы, но выжила. Сперва недомогание списали на основное заболевание, возможность радиационного «овердоза» начали рассматривать лишь год спустя. Вред здоровью был нанесен, но в сравнении с другими случаями — «незначительный».

Первое время AECL категорически отрицала возможность чрезмерного облучения пациентов аппаратом Therac-25 — «ведь мы проводили многолетнее тестирование». Позже были отсылки к неким экспертам, которые пришли к аналогичным выводам, — «но мы не можем назвать их имена». Независимое изучение вопроса показало, что это не так. Канадскую государственную корпорацию вынудили начать собственное настоящее расследование лишь после пятого инцидента.

В AECL до последнего пытались найти ошибки в «железе», практически не принимая во внимание код. В то же время, как утверждают некоторые специалисты, чтобы достичь заявленного уровня безопасности, инженерам компании пришлось бы тестировать систему на протяжении 100 тыс. лет. На деле же, по их словам, к тестированию относились спустя рукава, после внедрения исправлений софт не прогоняли через всевозможные испытания. А ведь шанс того, что что-то «сломается» после патча, достаточно велик — 50 на 50.

Наконец выяснилось, что все ошибки достались Therac-25 от Therac-20 и, вероятно, даже от Therac-6 (в котором рентгеновского режима не было вовсе). На старых системах баги никак не проявляли себя из-за аппаратных решений обеспечения безопасности. А в новой «продвинутой» системе стали очевидны — ничто не могло их «прехватить». И вот при разовой терапевтической дозе до 200 рад пациенты, как утверждают некоторые источники, получали до 20—25 тыс. рад (точечно, так как смертельная доза для всей поверхности тела в разы меньше).

Признать ошибку и остановить работу

В 1987 году американский и канадский регуляторы потребовали остановить работу всех Therac-25 (их насчитывалось чуть менее полутора десятков в США и Канаде) до выяснения обстоятельств. За полгода AECL составила план и утвердила его, внедрив аппаратные системы защиты и доработав ПО. Оставшиеся в живых жертвы и их родственники подали иски, однако все вопросы были улажены сторонами в досудебном порядке.

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

Ну а история Therac-25 стала уроком о том, как нельзя проектировать системы с повышенными требованиями к безопасности.

Список источников: Bugsnag, Hackaday, California Polytechnic State University, Stanford University, IEEE Computer Society, How Not To Code, ComputingCases, Wikibooks, Interesting Engineering, Virginia Tech.

Читайте также:

  • Жил в доме без горячей воды и «бежал от коммунизма». История украинского основателя WhatsApp Яна Кума
  • Sonnengewehr, или Как нацисты лучом света из космоса хотели сжигать города

Наш канал в Telegram. Присоединяйтесь!

Быстрая связь с редакцией: читайте паблик-чат Onliner и пишите нам в Viber!

Читайте нас в Дзене

Перепечатка текста и фотографий Onliner без разрешения редакции запрещена. nak@onliner.by

October 2 2015, 15:48

Categories:

  • Наука
  • Медицина
  • Происшествия
  • Cancel


(источник изображения)

Ошибка аппарата Therac-25 была одной из самых дорогих ошибок в современной истории — с июня 1985 по январь 1987 года шесть пациентов получили передозировку радиации, что привело к гибели троих из них.

Therac-25 представлял собой компьютеризированную машину для радиационной терапии, построенную компанией Atomic Energy of Canada Limited (AECL). Предшественниками Therac-25 были Therac-6, который представлял собой ускоритель на 6 миллионов электрон-вольт (МэВ), способный испускать только рентгеновские лучи, и Therac-20, рентгеновский излучатель и ускоритель электронов на 20 МэВ. Все три машины использовали мини-компьютер DEC PDP-11. И в Therac-6, и в Therac-20 использовались некоторые аппаратные возможности для предотвращения небезопасных операций. Некоторые программные модули из Therac-6 были использованы вновь в Therac-20 и Therac-25. Кроме того, в Therac-25 были использованы программные модули Therac-20 для электронного режима.

Therac-25 был усовершенствованием Therac-20. Он был способен испускать фотоны или электроны с энергией 25 МэВ с возможностью переключения уровней. Он был меньше, имел больше возможностей и был легче в использовании. Также он был сконструирован так, чтобы компьютерное управление было более полным, чем в его предшественниках. Программное обеспечение, разработанное для Therac-25, было способно осуществлять контроль состояния и управление оборудованием. Поэтому решено было удалить аппаратные средства безопасности и полагаться в этом вопросе на программное обеспечение.

Therac-25 поступил в продажу в конце 1982 года, и 11 таких машин были установлены в Северной Америке, 5 — в США и 6 — в Канаде. Шесть несчастных случаев с большими передозировками произошли между 1985 и 1987 годами.
—————
Во время почти всех инцидентов аппарат выдавал «ошибку 54».
—————
Оказалось, что передозировка возникала, если данные врачебного предписания редактировались в быстром темпе.

Как же было возможно, что быстрое редактирование вызывало передозировку? Аппарат Therac-25 мог работать в одном из двух режимов — фотонном или электронном. В электронном режиме оператору было необходимо ввести уровень энергии. Если же был выбран фотонный режим, по умолчанию энергия фотонов принималась за 25 МеV. Ошибки, совершенные оператором в обоих случаях, были одни и те же. Для двоих пациентов, которые получили передозировку, требовался электронный режим. Однако, поскольку большинству пациентов нужен фотонный режим, оператор привыкла выбирать последний. В этих двух случаях оператор первоначально выбирала фотонный режим, а затем исправляла свою ошибку. Физическая калибровка и настройка магнитов занимает около 6 секунд. Программный модуль, который проверяет завершение ввода данных, должен произвести калибровку магнитов, как только были установлены параметры режима и уровня энергии. Другой программный модуль был ответственен за проверку изменения входных данных. Если изменения были произведены, настройка магнита сбрасывалась и калибровка начиналась заново с новыми параметрами. Однако логическая ошибка в этом модуле вызывала то, что он был не способен распознать изменения данных, если они производились в течение восьми секунд после того, как были введены первоначально. (Это чрезвычайно упрощенное описание программного алгоритма. Советую читателю обратиться к отчету Levenson and Clark за дополнительными подробностями.) В этих двух случаях, когда оператор выбирала фотонный режим в первый раз, машина подготавливала к использованию уровень энергии в 25 MeV в фотонном режиме. А когда оператор изменила режим на электронный в течение восьми секунд, параметры магнитов не были сброшены и давалась неверная доза.

(ист)
_

Вы столкнулись со страшной бедой, и этот аппарат — ваш последний шанс на спасение. Доверите ли вы ему свою жизнь?

Therac–25 не из тех устройств, при виде которых люди радуются. Это аппарат лучевой терапии. Говоря простыми словами, «цеппер для рака», линейный ускоритель, чья мишень — человек. Используя рентгеновские лучи или пучки электронов, аппараты лучевой терапии уничтожают раковые клетки даже глубоко внутри организма. Эти аппараты размером с комнату всегда наносят побочный ущерб здоровым тканям вокруг опухолей. Как и в случае с химиотерапией, ставка делается на то, что суммарный эффект окажет пациенту больше пользы, нежели вреда. Но в 1986 и 1987 Therac–25 сделал немыслимое: аппарат подверг шестерых пациентов радиоактивной передозировке, в результате которой четверо из них погибли, а двое получили увечья на всю жизнь. В ходе расследования было установлено, что, во–первых, в программном обеспечении аппарата содержались ошибки, которые оказались смертельными. Во–вторых, конструкция аппарата в плане безопасности опиралась только лишь на управляющий компьютер. В самой конструкции не были предусмотрены механизмы блокировки или контрольные схемы, которые гарантировали бы, что ошибка в программном обеспечении не приведёт к катастрофическим сбоям.

В программном обеспечении Therac–25 содержался один из самых известных багов–убийц в истории. Несколько университетов приводят этот случай в качестве предостережения о том, что может пойти не так и как расследования могут вводить в заблуждение. Наибольший вклад в изучение этой проблемы сделала Нэнси Левенсон, эксперт безопасности программного обеспечения, она провела исчерпывающие исследования несчастных случаев и связанных с ними судебных исков. Большая часть информации, опубликованной о Therac–25 (включая эту статью), основана на её исследовании, проведённом совместно с Кларком Тёрнером, под названием «Расследование аварий Therac–25».

История и разработка

Therac–25 был создан канадской государственной организацией «Atomic Energy of Canada Limited» (далее AECL). Это был третий аппарат лучевой терапии на счету компании, предшествующие Therac–6 и Therac–20 были произведены совместно с французской компанией CGR. Когда пришло время проектировать Therac–25, партнёрство прекратилось. Тем не менее, у обеих компаний остался доступ к проектам и исходным кодам ранних моделей.

Программный код в Therac–20 основывался на коде Therac–6. На всех трёх аппаратах был установлен компьютер PDP–11. Однако предыдущим моделям он не требовался, так как они были спроектированы как автономные устройства. Техник по лучевой терапии настраивал различные параметры вручную, в том числе и положение поворотного диска для настройки режима работы аппарата.

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

На Therac–6 и 20 аппаратные механизмы блокировки не позволяли оператору сделать что–то опасное, скажем, выбрать электронный пучок высокой мощности без рентгеновской мишени на месте.

Попытка активировать ускоритель в неправильном режиме приводила к срабатыванию предохранителей и остановке работы. PDP–11 и сопутствующее оборудование были встроены для удобства. Техник мог ввести рецепт в терминал VT–100, и компьютер, используя сервоприводы, автоматически настраивал поворотный диск и другие устройства. Сотрудникам больниц нравилось, что компьютер настраивает всё быстрее, чем человек. Чем меньше времени уходило на настройку, тем больше пациентов можно было принять за день на аппарате ценой в несколько миллионов долларов.

Когда пришло время сделать Therac–25, AECL решили оставить только компьютерное управление. Они не только отказались от устройств ручного управления, но также и от аппаратных механизмов блокировки. Компьютер должен был следить за настройками устройства и, в случае обнаружения неполадок, должен был отключать питание всей машины.

Происшествия

Therac–25 ввели в эксплуатацию в 1983 году. За несколько лет он обслужил тысячи пациентов без каких–либо проблем. 3 июня 1985 года одна женщина проходила курс лечения от рака груди. Ей прописали 200 поглощённых доз ионизирующего излучения (рад) в виде электронного пучка 10 МэВ. Когда машина запустилась, пациентка почувствовала очень сильный ожог. Позже было уставлено, что она подверглась дозе от 10000 до 20000 рад. Пациентка выжила, но лишилась левой груди и руки из–за радиации.

Второй несчастный случай произошёл 26 июля в онкологическом Институте Онтарио в Канаде. Пациентка скончалась в ноябре того же года. Вскрытие установило, что смерть наступила в результате рака шейки матки. Но если бы пациентка выжила, ей понадобилось бы полное эндопротезирование тазобедренного сустава, чтобы исправить травму, нанесённую Therac–25.

В декабре 1985 произошёл третий несчастный случай в Якиме, штат Вашингтон. У пациентки на бедре остались ожоги в виде узора, который повторял полосы на аппарате, предназначенные для блокировки излучения. Пациентка выжила, но ей потребовалась кожные трансплантаты, чтобы залечить раны от радиационных ожогов.

21 марта 1986 года пациенту в Тайлере, штат Техас, назначили девятый сеанс лучевой терапии на Therac–25. Ему прописали 180 рад для лечения небольшой опухоли в спине. Когда аппарат включился, пациент почувствовал жар и боль, что было неожиданно, так как лучевая терапия обычно проходит безболезненно. Therac–25 стал издавать нехарактерный гудящий звук. Пациент попытался встать с процедурного стола и получил второй радиационный ожог. После чего он начал стучать по двери. Он получил сильную передозировку. Его госпитализировали с лучевой болезнью, и через пять месяцев он скончался.

11 апреля 1986 года в Тайлере снова произошёл несчастный случай. На этот раз пациент лечился от рака кожи уха. Аппаратом управлял тот же самый оператор, что и во время происшествия 21 марта 1986. Когда начался сеанс терапии, пациент увидел яркий свет и услышал звук, с которым жарится яичница на сковороде. У него было чувство, словно его лицо горит. Пациент умер спустя три недели от радиационных ожогов в правой части височной доли и стволе головного мозга.

Последний случай передозировки произошёл намного позже в больнице Якима Вэлли в январе 1987 года. Пациент скончался в результате
полученных повреждений.

Расследование

После каждого несчастного случая дозиметрист местной больницы связывался с AECL и управлением медицинского регулирования в соответствующих странах. Сначала AECL отрицал, что Therac–25 был способен вызывать передозировки излучения.

В аппарате было столько защитных гарантий, что он часто выдавал коды ошибок и приостанавливал свою работу, давая меньше назначенной дозы. После инцидента в Онтарио стало очевидно, что что–то не так. Единственная причина, по которой могла случиться такая передозировка — неправильное расположение поворотного диска. Если бы сканирующие магниты или рентгеновская мишень были в неправильном положении, пациента бы поразил луч радиации, подобный лазерному.

AECL проводили тестирование за тестированием, но не могли воспроизвести такую ошибку. Единственная возможная причина, которая приходила им в голову — временный отказ работы трёх микропереключателей, которые определяли положение поворотной платформы. Сеть микропереключателей была переконструирована таким образом, чтобы неполадки в работе любого из них определялись компьютером. Эту модификацию быстро добавили, но она не помогла предотвратить последующие инциденты.

Если в этой истории и есть герой, то это Фриц Хагер, дозиметрист онкологического центра в Тайлере. После второго происшествия на его объекте он решил докопаться до корня проблемы. В обоих случаях Therac–25 выводил на экран компьютера сообщение о «Неисправности–54». В пользовательском руководстве такая ошибка не упоминалась. AECL объяснили, что неисправность–54 указывала на то, что компьютер не мог определить, недостаточна ли дозировка излучения или, наоборот, она превышается.

В обоих случаях аппаратом управляла одна и та же женщина–техник лучевой терапии, и Фриц дал ей указание попробовать воссоздать такой случай в комнате управления. Вдвоём они «заперли двери» (прим пер.: среди работников НАСА эта кодовая фраза означает наступление нештатной ситуации, при которой никому не разрешается покидать помещение пультовой или входить в него, чтобы можно было сохранить всю имеющуюся информацию для последующего расследования) и всю ночь и все выходные пытались воссоздать проблему. Вместе они должны были обнаружить неполадки.

Консоль виртуального терминала, которая используется для ввода команд, разрешает перемещение курсора с помощью кнопок вверх и вниз.

При выборе рентгеновского режима аппарат начинал настраивать устройство для мощного рентгеновского излучения. Этот процесс занимал около восьми секунд. Если в течение этих восьми секунд оператор переключал аппарат в электронный режим, поворотный диск принимал неправильное положение.

Важно отметить, что все тестирования до этого момента проводились медленно и тщательно, как можно было ожидать. Из–за природы этой ошибки результаты таких тестирований никогда бы не смогли определить причину происшествий. Для этого требовался кто–то, кто хорошо знал аппарат, кто–то, кто работал с системой ввода данных каждый день до того, как нашли ошибку. Фриц продолжал работать до тех пор, пока не смог вызывать «Неисправность–54» по собственной воле. Даже с таким неопровержимым доказательством ему понадобилось совершить несколько звонков и отправить несколько факсов с подробными инструкциями для того, чтобы AECL смогли добиться подобного поведения аппарата в лабораторных условиях. Фрэнк Боргер, дозиметрист онкологического центра в Чикаго, доказал, что эта ошибка также существовала и в программном обеспечении Therac–20. Введя алгоритм задач, который установил Фриц на предыдущей модели аппарата, Боргер получил подобную ошибку, но в аппарате срабатывал предохранитель. Предохранитель был частью системы блокировки, от которой отказались в Therac–25.

По мере того, как продвигалось судебные разбирательства и расследование, программное обеспечение Therac–25 рассматривалось самым пристальным образом. PDP–11, установленный на Therac–25, был полностью запрограммирован на языке ассемблера. Не только приложение, но и лежащая в основе операционная система. Задачей компьютера было управление аппаратом в реальном времени, он отвечал как за эксплуатацию в обычном режиме, так и за систему безопасности. Сегодня с таким типом работы справляется один или два микроконтроллера, а компьютер обеспечивает работу графического пользовательского интерфейса.

AECL не выкладывала исходный код в открытый доступ, но несколько экспертов, в том числе Нэнси Левинсон, получили доступ для проведения расследования. То, что они обнаружили, их шокировало. Программное обеспечение было написано программистом, у которого почти не было опыта работы с системами, работающими в реальном времени. Со стороны компании было несколько заявлений, но никаких доказательств того, что проводился временной анализ. Согласно AECL, всё программное обеспечение написал один программист, взяв за основу код Therac–6 и 20. Однако он больше не работал в компании, и найти его не удалось.

Последствия

Управление по санитарному надзору объявило о том, что Therac–25 неисправен. AECL выпустили патчи и обновления для оборудования, которые в итоге позволили аппаратам вернуться на службу. Все иски были урегулированы во внесудебном порядке. Казалось, что все проблемы решены, пока 17 января 1987 года ещё один пациент не получил передозировку в Якиме, штат Вашингтон. На этот раз проблема была в другом: переполнение счётчика. Если оператор отправлял команду в момент, когда счётчик переполнялся, машина пропускала некоторые настройки излучения, например, не приводила в правильное положение стальной отражатель системы наведения. В результате чего луч не считывался, что приводило к передозировке. Пациент умер спустя три месяца.

Важно отметить, что софт был основополагающим фактором в Therac–25, а не главной причиной. Весь проект системы был одной большой проблемой. Компьютерная система подвергалась критическим, с точки зрения безопасности, нагрузкам, на которые не была рассчитана. Временной анализ не проводился, как и модульное тестирование. Не составлялись диаграммы всех возможных последствий несрабатывания системы ни для софта, ни для железа. За это должны были отвечать не только специалисты по программному обеспечению, но и инженеры–разработчики систем по проекту. Therac–25 уже давно списали, но его наследие будет жить. Это было эпохальное событие, которое наглядно всем продемонстрировало, что может пойти не так, если софт для жизненно важных систем не проектируется должным образом и не тестируется как следует.

http://muz4in.net/news/mashina_ubijca_therac_25/2015-11-09-39570

Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

VPS с гибкой конфигурацией: за 1€

Мощные выделенные сервера: от 25€

Собственный Дата-Центр
Поддержка 24/7

Виртуальные серверы VPS/VDS в России, Европе и США!

Промокод citforum — скидка 10% на заказ сервера!

☁️ Виртуальные серверы от 95 ₽

🖥 Хостинг сайтов PHP от 25 ₽

💰 Скидка 15% по промокоду CITFORUM на первый платёж!


Виртуальные VPS серверы в РФ и ЕС

Dedicated серверы в РФ и ЕС

По промокоду CITFORUM скидка 30% на заказ VPSVDS

2005 г.

Изучение знаменитых (и не очень знаменитых) ошибок

Глава из книги «Наука отладки»

Мэтт Тэллес, Юань Хсих
Пер. с англ. С. Лунин, науч.ред. С. Брудков
Издательство: КУДИЦ-ОБРАЗ

Полное содержание книги

Глава 2

Yuan Hsieh

  • Сценарий
  • Распределенные компьютерные системы из «реальной жизни»
    • ИСТОРИЯ: КОМПАНИЯ Y
    • ИСТОРИЯ: КОМПАНИЯ Х
    • ВЫВОДЫ
  • Therac-25
    • ИСТОРИЯ
      • Kennestone Regional Oncologyl Center, г Кенстоун, округ Мариетта, штат Джорджия (Kennestone, Marietta, Georgia). Июнь 1985
      • Ontario Cancer Foundation, Хемилтон, провинция Онтарио, Канада (Hamilton, Ontario, Canada)
      • Yakima Valley Memorial Hospital, Якима, штат Вашингтон (Yakima, Washington), декабрь 1985
      • East Texas Cancer Center (Восточно-Техасский онкологический центр), г Тайлер, штат Техас (Tyler, Texas). Март 1986
      • East Texas Cancer Center (Восточно-Техасский онкологический центр), г Тайлер, штат Техас (Tyler, Texas). Апрель 1986
      • Yakima Valley Memorial Hospital, г Якима, штат Вашингтон (Yakima, Washington), Январь 1987
    • Выводы
  • Зарисовка #1
    • ОШИБКА В ПРОЦЕССОРЕ INTEL PENTIUM
    • ИСТОРИЯ
    • ВЫВОД
  • Зарисовка #2
    • Ariane 5 Ошибка операнда
    • ИСТОРИЯ
    • ВЫВОД
  • Зарисовка #3
    • Аппарат для исследования климата Марса
    • История
    • Вывод
  • Зарисовка #4
    • Авария на телефонной компании AT&T
    • История: Авария 1990 года
    • Вывод: Авария 1990 года
    • История: Авария 1998 года
    • Вывод: Авария 1998 года
    • Переполнение буфера
    • История
    • Вывод
  • Заключение
    • Задача

Представьте, что сейчас 1986 год. И представьте, что вы — ныне покойный Ричард Фейнман (Richard Feynman). Звонит телефон, вы поднимаете трубку. Звонит Уильям Грэхэм (William Graham), исполняющий обязанности администратора в NASA1. Вы знаете, что это не может быть просто дружеский звонок, поскольку космический челнок Челленджер потерпел катастрофу несколько дней назад, 28 января 1986 года. Вы правы. Он звонит для того, чтобы просить вас принять участие в работе комиссии по исследованию причин катастрофы Челленджера. В сущности, NASA просит вас, свежеиспеченного Нобелевского лауреата, выступить в роли главного исследователя неисправностей для одного из самых печальных инцидентов в NASA в современной истории2. Вы принимаете предложение с трепетом. В конце концов, вы можете быть Нобелевским лауреатом, но вы не специалист по ракетам. Вы не участвовали в разработке космического челнока. Вы не знакомы с компонентами и системами космического корабля. Вы не имеете представления, какого рода информация записывалась в ходе рокового полета Челленджера. Вы не представляете себе состояние или полезность документации. Единственный ключ, который у вас есть, — это ваши визуальные наблюдения, что пламя, как кажется, выходило из правого топливного бака. Как вы будете решать задачу по поиску причины катастрофы?

В действительности, доктор Фейнман обнаружил причину инцидента, перемещаясь по всей стране и беседуя с инженерами и персоналом и не поддаваясь политическому давлению. В конечном итоге он провел свой знаменитый настольный эксперимент с образцом от одного из уплотнительных колец с челнока и стаканом ледяной воды для доказательства своей теории3 в ходе пресс-конференции в прямом эфире4.

К счастью, наша работа по устранению ошибок в программных системах намного легче той задачи, с которой столкнулся доктор Фейнман. В большинстве случаев мы можем попытаться воспроизвести ошибку, чтобы удостовериться, что мы полностью понимаем ее причины и следствия. Ученые NASA не имели такого преимущества. Они не могли воспроизвести ошибку, взорвав другой космический корабль. Более того, доктор Фейнман должен был представить формальный отчет о своих открытиях для общественной поверки и, что еще хуже, должен был бороться с политическим давлением со стороны официальных лиц NASA. Когда в последний раз мы должны были делать нечто подобное при устранении ошибок? В индустрии программного обеспечения мы очень мало делаем того, что можно назвать посмертным анализом ошибки. Мы не задаем таких вопросов, как, каким образом ошибка была обнаружена, как она возникла и что мы можем сделать, чтобы предотвратить ее. Если мы все же проводим посмертный анализ, мы так редко документируем наши открытия, что наше знание недоступно другим людям.

Во многих смыслах наша книга — это кульминация многих лет посмертного анализа ошибок, о которых мы узнали и которые провели сами. В главе 12 мы покажем вам, как анализировать ошибки, как увеличить ваше коллективное знание о процессах формирования ошибок и как это знание поможет нам избежать одних и тех же ошибок и создавать лучшее программное обеспечение в будущем. Действительно ли посмертный анализ ошибки поможет нам создать лучший продукт? Мы считаем, что ответ на этот вопрос — да! В 1981 году фирма NEC осуществила план, призванный помочь разработчикам программ и менеджерам проектов учиться на ошибках. Был создан каталог ошибок, наблюдавшихся во многих корпоративных проектах. Это поддержало разработчиков в поисках причин отказов программ и в предотвращении их повторного появления. За 10 лет, прошедших с запуска проекта, разработчики извлекли много уроков и стали способны применять этот опыт для повышения своей производительности и понижения числа ошибок5.

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

Сценарий

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

Распределенные компьютерные системы из «реальной жизни»

Парад ошибок начинается примерами с двух моих предыдущих мест работы. Первая ошибка просуществовала несколько часов и была быстро устранена. Это был урок для второй ошибки. Девять месяцев спустя, вскоре после того как я начал работать в другом месте, я столкнулся с похожей ошибкой. Однако в новой компании проблема проявила себя за два месяца до моего прихода. Серьезность первой ошибки была такова, что она нарушала работу всей системы. Вторая ошибка, хотя и устойчивая, не была фатальной, она просто вызывала легкое раздражение, а не общую катастрофу.

История: компания Y

Был конец 1999 года, и я работал в одной Интернет-компании, которая обслуживала финансовые отчеты в Интернете. Назовем ее компания Y. Архитектура систем, обслуживающих финансовые отчеты, очень проста: Web-запрос приходит через один из многочисленных Web-серверов. Web-сервер передает запрос менеджеру нагрузки, и менеджер нагрузки доставляет запрос к одному из четырех серверов отчетов циклическим образом. Сервер отчета выбирает информацию из базы данных для генерации отчета.

Однажды сигналы тревоги начали сыпаться со всех сторон. Сервера отчетов выходили из строя один за другим. Сервер останавливался, перезапускался несколькими минутами позже и снова останавливался через несколько минут. Это случалось со всеми серверами. Частота поступления запросов не была очень высокой, не была она и какой-то необычной. Перезагрузка машины, кажется, не помогала. Сетевые операторы не имели представления, что вызвало этот хаос, и была вызвана команда разработчиков. Поскольку я разрабатывал и реализовывал коммуникационную инфраструктуру, используемую внутренними серверами, меня попросили помочь. Команда разработчиков подозревала, что модуль распределения нагрузки в коммуникационной инфраструктуре был неисправен и сервера останавливались из-за перегрузки.

Коммуникационная инфраструктура имела встроенные возможности протоколирования и трассировки, которые были деактивированы в конечном продукте. Первое, что я сделал, это включил эти возможности, чтобы определить, что же система делает. Протокол, сформированный сервером отчетов, мало что прояснил для меня. В протоколе была масса сообщений об ошибках, но ни одно из этих сообщений ничего не описывало. Однако сразу перед тем, как сервер отчетов претерпевал сбой и перезапускался, в протокол попадало сообщение, что сервер отчета остановлен. Я спросил у инженера, что означает это сообщение, но его ответ был несколько загадочным. Это было что-то о том, что программа перезапускает себя, когда считает, что есть какая-то проблема. В это время я рассматривал файлы протоколов, полученных от менеджера нагрузки, и увидел, что он все время обращается к одному и тому же серверу. Я немедленно предположил, что механизм распределения нагрузки работает неправильно и что менеджер загрузки перегружает сервер отчета, заставляя его перезапускать себя.

Я проинформировал группу о моих предположениях и вернулся к своему столу, проверять код, выискивая потенциальные ошибки. Ничего не бросалось в глаза, и я подумал о замечании инженера, что сервер отчета разработан так, чтобы перезапускаться, когда он считает, что существует проблема. Я решил выяснить, какого рода проблемы могли бы вынудить сервер перезапуститься. По существу сервер отчетов поддерживал 20 потоков одновременно и каждый запрос к серверу занимал 1 процесс. Ожидалось, что в нормальных условиях каждый процесс заканчивает обработку в течение 1-2 секунд. Данный сервер отчета не считался очень стабильным и имел факты подверженности ошибкам. Поэтому в сервер была встроена логика «безопасности», так, что, если в момент, когда все 20 процессов были заняты, поступал 21-й запрос, этот последний должен был ожидать освобождения потока в течение 5 секунд. Если срок ожидания у этого запроса истекал, сервер отчета считал, что что-то не так и что все 20 потоков зависли. Единственным действием дальше становилась остановка и перезагрузка сервера.

Услышав это, я вернулся к своему столу, чтобы все обдумать. Через несколько минут все встало на свои места. Я проверил свои размышления файлами протоколов и трассировок и сообщил мою гипотезу группе, обслуживающей сервер отчетов.

  • Причина того, что менеджер нагрузки работал только с одним сервером отчетов, была не в том, что алгоритм распределения нагрузки был ошибочным. Он работал только с одним, поскольку остальные были недоступны. Они все перезапускались. Это было легко проверить, взглянув на временные отметки файлов протокола с серверов отчета и менеджера нагрузки.
  • Протоколы серверов отчета показывали, что запускалась логика «безопасности». Это подразумевало, что у каждого сервера было по 21 конкурирующему процессу. Это означало, что в некоторый момент времени к системе поступило 84 запроса, поскольку к моменту инцидента работали 4 сервера отчетов.
  • В конечном итоге один из серверов перезапускался из-за запуска логики «безопасности». Это в результате снижало пропускную способность системы до 63 запросов. Однако скорость поступления запросов оставалась постоянной. Это еще увеличивало нагрузку на оставшиеся 3 сервера, и в конечном итоге другой сервер перезапускался из-за логики «безопасности». Пропускная способность падала до 42 запросов. К тому времени, когда первый сервер заканчивал перезагрузку, останавливался и начинал перезапуск третий. Этот эффект мог сохраняться сколь угодно долго, если ничего не менялось, и скорость поступления запросов и скорость ответа оставались постоянными.

Эта гипотеза соответствовала наблюдениям, что сервера перезапускались последовательно, и тому, что они просто не были способны оставаться функциональными. Однако нам еще следовало определить причину перегрузки 84 запросами. Мы уже проверяли, что нагрузка не была чрезвычайно высокой. Оставалась только одна возможность. Проблема должна была быть связана с допущением того, что каждый запрос обрабатывается за 1-2 секунды и что 21-й запрос должен подождать только 5 секунд. Это выбранное значение, по-видимому, было ошибочно. Это допущение является верным в нормальных условиях работы. В начале этого описания я сказал, что сервер при генерации отчета зависит от базы данных. В данном случае база данных претерпевала что-то вроде деградации (meltdown). Мы так и не смогли определить причины такой деградации. Простая команда SELECT вместо десятых долей секунды занимала до 10 секунд. Сильное падение производительности базы данных проявило ошибку проектирования системы, и ситуация быстро ухудшалась. Поскольку каждый сервер отчета, который останавливался, снижал общую пропускную способность, большая нагрузка оказывалась на оставшиеся рабочие сервера. Если не вмешиваться, то проблема просто бы исчезла, когда нагрузка упала бы до величин, меньших 20 одновременно обрабатываемых запросов ко всей системе.

Как только было определено, что сервер базы данных работает неверно, перезагрузка SQL сервера решила проблему.

История: компания Х

В середине 2000 года я начал работать в другой Интернет-компании, которая занималась картографической и деловой информацией, а также электронной коммерцией. Назовем ее Компанией Х. Системная инфраструктура в Компании Х была сходна с инфраструктурой в Компании Y: Web-сервера обращались к менеджерам нагрузки, которые обращались к агентам баз данных, которые и связывались с базами. Однако существовало небольшое усложнение в том, что Компания Х предоставляла интерфейс интерактивного голосового ответа (Interactive Voice Response, IVR), который позволял клиентам осуществлять доступ к системе через обычный телефон. Инфраструктура, которая реализовывала IVR, просто замещала Web-сервер IVR-сервером, который связывался с менеджером нагрузки таким же образом, как и Web-сервера. Другое отличие состояло в том, что Компания Х задействовала два отдельных центра данных. Обычно IVR-сервер использовал один центр в качестве первичной и активной системы. Когда возникали сложности с активным центром, IVR-сервер переключался на другой, запасной центр.

Однажды руководитель технического отдела Компании Х пришел, чтобы попросить меня поговорить с группой, обслуживающей IVR-сервер, и помочь им исследовать недавний выход службы из строя. Несколькими днями ранее работа IVR-системы была нарушена более чем на восемь часов. Когда я пришел поговорить с группой, выяснилось, что для продолжения работы информации очень мало. Были файлы протокола с IVR-сервера на момент выхода его из строя, но они были удалены из-за проблем коммуникации с Центром сетевых операций. Люди, занимавшиеся обслуживанием системы, подозревали, что ошибка была связана с какой-то малопонятной сетевой проблемой центра данных. Однако это не объясняло, почему не использовался запасной центр. После дальнейших исследований оказалось, что проблема в IVR-сервере возникала при соединении с одним из центров данных. Эта проблема сохранялась в течение двух месяцев.

Поскольку я был не знаком с системой, я попросил показать мне сгенерированные файлы протоколов. Я хотел быть способным зафиксировать поведение системы, когда (и если) сбой возникнет опять. Файл протокола, хотя и полезный для просмотра ошибок, не очень помогает в описании действий системы. Он только отображает статус каждого запроса, после того как он был обработан. Если бы какой-нибудь запрос вызвал ошибку, файл протокола никогда не показал бы состояние IVR-сервера в момент сбоя. Более того, IVR-сервер не выходил из строя при сбое системы. Не было ни одного базового файла, который можно было бы использовать. Однако файл протокола показывал относительно большое число событий при переключении IVR-сервера от одного центра данных к другому. Каждое событие переключения центров данных имело корреляцию с серией из трех запросов со статусом кода ошибки -3, кода, который означал, что время ожидания у запроса истекло, когда IVR-сервер пытался соединиться с менеджером нагрузки. В Компании Х каждый запрос имел уникальный идентификатор (ID), который заносился в файл протокола на любом сервере, к которому этот запрос обращался, так что была возможность проследить путь запроса в системе. Однако IVR-сервер не записывал ID запроса в свой протокол, так что мы не могли выяснить, почему истекло время ожидания.

Наученный опытом, полученным в Компании Y, я спросил о стратегии преодоления ошибок на IVR-сервере. Оказалось, что IVR имеет требования к быстродействию — в отличие от использования Web-сайтов, при использовании телефона люди не любят ждать. Поэтому IVR должен ответить в течение определенного времени. IVR-сервер должен был получить данные от менеджера нагрузки в течение трех секунд. После трех последовательных, закончившихся неудачей попыток сервер автоматически переключался на запасной центр данных. Оставаясь соединенным с запасным центром данных, IVR-сервер через 2 часа пытался восстановить соединение с первичным центром данных. Если попытка оказывалась успешной, сервер вновь переключался на первичный центр данных.

К этому времени у меня были две довольно разумные гипотезы, которые объясняли все наблюдения. (1) Поскольку проблемы на IVR-сервере были при соединении с одним из центров данных, по всей видимости, IVR-сервер работал без резерва. Если бы на центре данных, к которому он был подключен, возникли проблемы, служба IVR оказалась бы недоступной. И (2) причина того, что IVR-сервер не мог поддерживать соединение с центром данных, была точно записана в существующем файле протокола. Это было истечение времени ожидания его запросов. Чтобы определить, почему время ожидания заканчивается так часто, нам следовало проследить путь запросов, которые вызывали его.

Не было, однако, протоколов или другой информации, чтобы проверить мои гипотезы, поэтому я совместно с командой обслуживания IVR-сервера начал работу по генерации более полезного протокола. Как только мы оказались способны проследить поток запросов через систему, сразу стало видно, где здесь узкое место. Один из серверов базы данных тратил необычно долгое время на обработку запросов. Этот сервер делал несколько SQL запросов к базе данных, которая располагалась на той же машине, что и сам сервер. Продолжительность вызовов была существенно выше, чем ожидалось. Поскольку на сервере базы данных была видна необычно высокая загрузка процессора, было сделано предположение, что машина слишком перегружена и, возможно, необходимо дополнительное оборудование. Другая гипотеза состояла в том, что SQL-операторы, как они были реализованы, являлись неэффективными. Это необходимо было проверить. Еще несколько дней исследований выявили, что база данных обновлялась за 2 месяца до инцидента. Однако администратор базы данных забыл переиндексировать базу, и каждый запрос занимал в 10 раз больше времени на обработку, чем обычно. Сильная нагрузка на процессор просто отражала выполнение SQL-операторов на неиндексированной базе. База на «рабочем» центре данных была обновлена и переиндексирована, поэтому никаких неприятностей не возникло. Мы никогда бы не смогли правильно объяснить причины сбоя, поскольку не было информации для исследований. Однако главной причиной сбоя было отсутствие запасного сервера данных.

Выводы

Сходство между предыдущими двумя случаями поразительно. В обоих случаях участвовали системы, которые были работоспособными долгое время. Обе системы работали как положено и не содержали ошибок реализации. Устранение проблемы в обоих случаях (по крайней мере, быстрое) состояло просто в перезапуске или переиндексировании базы данных. Обе проблемы проявились, поскольку ответы баз данных занимали больше времени, чем ожидалось. Причины проблем были хорошо видны в файлах протокола. Однако было трудно отследить в файлах и понять эти причины. Почему?

  • Компонентное мышление. — В обоих случаях инженеры концентрировались главным образом на компонентах. Они никогда не рассматривали наблюдения в контексте целой системы. Наладка в распределенной компьютерной среде требует целостного подхода. Каждый компонент системы может влиять на поведение другого компонента и системы в целом. Взаимосвязи между компонентами могут быть очень сложными и часто непонятными интуитивно. Когда вы интересуетесь, почему компонент вышел из строя, может быть, полезно задать вопрос: «Какой другой компонент системы мог вызвать сбой этого компонента?»
  • Ориентировка по вторичным признакам. — Несколько лет назад я участвовал в занятиях по лавинной безопасности. Одной темой этих занятий было проведение поиска с помощью радиомаяков. Идея такого поиска заключалась в том, что, если жертву засыпало снегом, ее радиомаяк посылал радиосигнал, который приемник на другом радиомаяке мог принять. В приемнике радиосигнал преобразовывался в звуковой сигнал. Чем громче был звук, тем ближе была жертва. Первоначально у меня были проблемы с поиском. Вместо того чтобы слушать звуковой сигнал и следовать по нему, я искал видимые признаки. Как только мне удалось отбросить все мои прочие чувства и сфокусироваться на звуке, спасение жертвы у меня существенно ускорилось. Тот же самый совет будет полезен при наладке приложений. В обоих наших примерах инженеры игнорировали подсказки, которые давали им их системы. Вместо того чтобы следовать этим подсказкам, они выбрали ориентировку по вторичным признакам и создавали некорректные гипотезы, не объяснявшие всех наблюдений. Все подсказки и все наблюдения нужно принять во внимание при создании гипотезы.
  • Игнорирование подсказок. — Важные подсказки игнорировались. В компании Х повышенную нагрузку на процессор у сервера базы данных нужно было исследовать, поскольку скорость поступления запросов не превышала нормальной. Неприемлемое время вызова и обработки запроса у сервера базы записывались в файлы протокола в течение двух месяцев, пока проблема сохранялась. Было множество предупреждений, что нечто плохое потенциально может случиться. Однако из-за недостатка времени, ресурсов и инфраструктуры на эти предупреждения не обращали внимания, пока не случилась катастрофа.

В этих двух инцидентах не были задействованы программные ошибки в традиционном смысле этого слова, хотя даже разработчики были поставлены в тупик. Проблемы, с которыми столкнулись Компании Х и Y, можно было предотвратить, если бы обслуживающий персонал был лучше информирован. Каким образом?

  • Лучшие инструменты мониторинга. — В обоих случаях, если бы обслуживающий персонал смог обнаружить и зафиксировать необычное поведение сервера базы данных, возможно, они смогли бы предпринять действия для корректировки сервера базы данных. Проблемы, с которыми мы столкнулись, могли бы никогда не проявиться.
  • Следование правилам. — В Компании Х существовало стандартное правило переиндексировать базу данных после ее обновления. В данном случае переиндексирование не было произведено и не было никаких записей об обновлении.

Недостаток записей сделал трудным определение изменений в окружении и в системе для нужд наладки.

Therac-25

Ошибка аппарата Therac-25 была, пожалуй, самой дорогой ошибкой в современной истории. Как известно, с июня 1985 по январь 1987 года шесть пациентов получили передозировку радиации, что привело к гибели троих из них. Здесь мы полностью полагаемся на отчет, опубликованный Leveson и Turner в 1993 году после нескольких лет расследования. Этот отчет содержит наиболее тщательную и детальную оценку причин и следствий инцидента с Therac-25 и охватывает все аспекты безопасности системы. Однако, поскольку наша книга посвящена программным ошибкам, мы ограничим наше изложение и анализ результатами, связанными с программным обеспечением6.

История

Therac-25 представлял собой компьютеризированную машину для радиационной терапии, построенную компанией Atomic Energy of Canada Limited (AECL). Предшественниками Therac-25 были Therac-6, который представлял собой ускоритель на 6 миллионов электрон-вольт (МэВ), способный испускать только рентгеновские лучи, и Therac-20, рентгеновский излучатель и ускоритель электронов на 20 МэВ. Все три машины использовали мини-компьютер DEC PDP-11. И в Therac-6, и в Therac-20 использовались некоторые аппаратные возможности для предотвращения небезопасных операций. Некоторые программные модули из Therac-6 были использованы вновь в Therac-20 и Therac-25. Кроме того, в Therac-25 были использованы программные модули Therac-20 для электронного режима.

Therac-25 был усовершенствованием Therac-20. Он был способен испускать фотоны или электроны с энергией 25 МэВ с возможностью переключения уровней. Он был меньше, имел больше возможностей и был легче в использовании. Также он был сконструирован так, чтобы компьютерное управление было более полным, чем в его предшественниках. Программное обеспечение, разработанное для Therac-25, было способно осуществлять контроль состояния и управление оборудованием. Поэтому решено было удалить аппаратные средства безопасности и полагаться в этом вопросе на программное обеспечение.

Therac-25 поступил в продажу в конце 1982 года, и 11 таких машин были установлены в Северной Америке, 5 — в США и 6 — в Канаде. Шесть несчастных случаев с большими передозировками произошли между 1985 и 1987 годами7.

Kennestone Regional Oncologyl Center, г. Кенстоун, округ Мариетта, штат Джорджия (Kennestone, Marietta, Georgia). Июнь 1985

Женщина в возрасте 61 года была направлена в онкологический центр для дополнительного лечения аппаратом Therac-25 после хирургического удаления молочной железы. Как считается, пациентка получила одну или две дозы радиации от 15 000 до 20 000 рад (поглощенная доза радиации). Для сравнения, типичная разовая терапевтическая доза радиации составляет до 200 рад. Кенстоунская клиника использовала Therac-25 с 1983 года без происшествий. Техники и фирма AECL не поверили, что эта проблема может быть вызвана Therac-25. В конечном итоге пациентка потеряла грудь, а также возможность пользоваться руками и плечами из-за радиационного поражения.

Ontario Cancer Foundation, Хемилтон, провинция Онтарио, Канада (Hamilton, Ontario, Canada)

Клиника в Хэмилтоне использовала Therac-25 в течение шести месяцев до инцидента с передозировкой. Сорокалетняя женщина поступила в клинику на 24-й сеанс лечения аппаратом Therac-25. Аппарат отключился через пять секунд после того, как оператор запустил его. Операторы были знакомы с частыми неполадками машины. Эти неполадки, вероятно, не имели серьезных последствий для пациента. Поскольку машина показывала, что облучение не было произведено, оператор попытался повторить его. Были произведены пять попыток. После пятой попытки был вызван техник, не обнаруживший проблем в аппарате.

Об инциденте сообщили в AECL, но воспроизвести неполадку и сделать заключение о причинах такого поведения Therac-25 не удалось. Однако благодаря этому сообщению фирма AECL обнаружила некоторые слабости конструкции и потенциальные механические проблемы в позиционировании поворотной платформы Therac-25 и были сделаны исправления. Пациентка умерла через пять месяцев. Результаты вскрытия показали, что смерть наступила от рака, а не от передозировки радиации. Однако вскрытие также выявило серьезные поражения бедра, вызванные радиационным воздействием. Как было позже определено, пациентка получила дозу порядка 13 000 — 17 000 рад8.

Yakima Valley Memorial Hospital, Якима, штат Вашингтон (Yakima, Washington). Декабрь 1985

После лечения аппаратом Therac-25 у женщины развилось сильное покраснение кожи в форме параллельных полос. Персонал клиники считал, что это явление мог вызвать Therac-25. Однако они не смогли воспроизвести конфигурацию оборудования, которая была использована при лечении пациентки. Персонал проинформировал AECL о потенциальной передозировке. В AECL снова посчитали, что передозировка при использовании аппарата Therac-25 невозможна. Персонал клиники не был осведомлен о двух предыдущих случаях и не имел возможности расследовать инцидент, поэтому они не стали продолжать дело после ответа из AECL. Пациентка, вероятно, получила более низкую дозу радиации, чем два предыдущих пострадавших, и она не испытала серьезных последствий в результате передозировки9 .

East Texas Cancer Center (Восточно-техасский онкологический центр), г. Тайлер, штат Техас (Tyler, Texas). Март 1986

Восточно-техасский онкологический центр использовал аппарат Therac-25 с 1984 года и применял его при лечении более 500 пациентов. 21 марта 1986 года пациент (мужчина) был направлен на дополнительное лечение. Оператор, которая осуществляла лечение, была знакома с Therac-25 и хорошо разбиралась в его свойствах и в процессе использования. Когда она вводила данные пациента и врачебные предписания, она допустила ошибку, которую быстро исправила и начала лечение. Спустя мгновение машина отключилась, и дисплей отобразил сообщения об ошибках. Как обычно происходит в программных системах, сообщение об ошибке представляло собой код, который никто не смог бы расшифровать. «Ошибка 54» расшифровывалась в печатном перечне ошибок как «ввод дозы 2». Восточно-техасский онкологический центр не располагал другой документацией, которая объясняла бы смысл выражения «ввод дозы 2». Дисплей показал также очень малую дозу облучения и, поскольку оператор была знакома с капризами Therac-25, она немедленно запустила повторное лечение. Машина снова отключилась с теми же сообщениями об ошибках.

Клиника связалась с AECL по поводу этой проблемы. Техники фирмы, направленные в Восточно-техасский онкологический центр, не смогли воспроизвести неисправность, и AECL все так же считала, что передозировка на Therac 25 невозможна. Пациент умер от осложнений передозировки через пять месяцев после этих событий10 .

East Texas Cancer Center (Восточно-техасский онкологический центр), г. Тайлер, штат Техас (Tyler, Texas). Апрель 1986

Три недели спустя другой мужчина поступил для лечения с помощью Therac 25. Та же женщина-оператор, которая участвовала в прошлом инциденте, была ответственной за лечение. Как и в предыдущем случае, она сделала ошибку при вводе данных, и, почти столь же быстро исправив ошибку, она запустила лечение. Машина ответила сообщением «ошибка 54» и отключилась. Однако пациент уже получил передозировку, и оператор побежала за помощью. Therac-25 был отключен, и клиника проинформировала AECL о втором случае передозировки.

Физик клиники, Фриц Хэгер (Fritz Hager), совместно с оператором научились воспроизводить сообщение «ошибка 54» произвольно. Оказалось, что передозировка возникала, если данные врачебного предписания редактировались в быстром темпе. Люди из AECL наконец смогли воспроизвести ошибку и признали, что передозировка была возможна11.

Как же было возможно, что быстрое редактирование вызывало передозировку? Аппарат Therac-25 мог работать в одном из двух режимов — фотонном или электронном. В электронном режиме оператору было необходимо ввести уровень энергии. Если же был выбран фотонный режим, по умолчанию энергия фотонов принималась за 25 МеV. Ошибки, совершенные оператором в обоих случаях, были одни и те же. Для двоих пациентов, которые получили передозировку, требовался электронный режим. Однако, поскольку большинству пациентов нужен фотонный режим, оператор привыкла выбирать последний. В этих двух случаях оператор первоначально выбирала фотонный режим, а затем исправляла свою ошибку. Физическая калибровка и настройка магнитов занимает около 6 секунд. Программный модуль, который проверяет завершение ввода данных, должен произвести калибровку магнитов, как только были установлены параметры режима и уровня энергии. Другой программный модуль был ответственен за проверку изменения входных данных. Если изменения были произведены, настройка магнита сбрасывалась и калибровка начиналась заново с новыми параметрами. Однако логическая ошибка в этом модуле вызывала то, что он был не способен распознать изменения данных, если они производились в течение восьми секунд после того, как были введены первоначально. (Это чрезвычайно упрощенное описание программного алгоритма. Советую читателю обратиться к отчету Levenson and Clark за дополнительными подробностями.) В этих двух случаях, когда оператор выбирала фотонный режим в первый раз, машина подготавливала к использованию уровень энергии в 25 MeV в фотонном режиме. А когда оператор изменила режим на электронный в течение восьми секунд, параметры магнитов не были сброшены и давалась неверная доза.

Когда в фирме AECL поняли ошибку, фирма немедленно разослала письмо к пользователям, в котором рекомендовала временные меры, заключавшиеся в том, чтобы не редактировать данные в ходе процесса их ввода.

Пациент скончался через три недели после инцидента от передозировки радиации12.

Yakima Valley Memorial Hospital, г. Якима, штат Вашингтон (Yakima, Washington). Январь 1987

К этому времени проблемы с машиной Therac-25 были преданы широкой гласности, по крайней мере в сообществе пользователей. Операторы знали о запрете редактировать данные. В то время когда AECL совместно с Управлением по контролю за продуктами и лекарствами (FDA) активно занималась планом работ по устранению неполадок, случился шестой инцидент. В данном случае пациент должен был получить три дозы облучения. Первые две дозы составляли 4 и 3 рад. Следующая доза составляла 79 рад в фотонном режиме. Первые два сеанса прошли без осложнений. После второй дозы оператор вошел в комнату облучения, чтобы повернуть поворотную платформу, чтобы проверить положение лучевого пучка относительно тела пациента. Оператор нажал кнопку возле поворотной платформы для указания того, что контроль произведен. Установив платформу, оператор запустил процесс лечения. Машина остановилась через 5-6 секунд, и поэтому оператор запустил лечение снова. И снова машина отключилась и отобразила «маловразумительную» причину остановки. Возникло предположение о передозировке, однако дисплей показал только облучение в 7 рад от двух первых сеансов.

Через неделю AECL обнаружила недостаток в программном обеспечении, который смог объяснить это поведение. Этот программный дефект отличался от того, который был обнаружен в Восточно-техасском онкологическом центре в деталях. Однако оба дефекта были вызваны неожиданными зависимостями от скорости в программных модулях. В данном случае существовала разделяемая переменная, названная Class3, содержащая однобайтовое значение. Это значение указывало, соответствуют ли параметры машины параметрам лечения. Если значение Class3 было ненулевым, параметры считались несоответствующими, и пучок лучей подавлялся. Эта переменная инициализировалась в модуле, который готовил машину к лечению. Однако инициализация заканчивалась инкрементированием данной переменной. Поскольку переменная была однобайтовой, через каждые 256 итераций значение ее доходило до нуля, программный модуль, проводивший инициализацию, запускался все время в зависимости от других событий в системе. Если кнопка на поворотной платформе была нажата именно в тот момент, когда переменная Class3 была равна нулю, проверка соответствия не производилась, и машина могла облучить пациента электронным пучком дозой до 25МеV.

Пациент умер в апреле 1987 году от осложнений, вызванных передозировкой. Машина была отозвана вскоре после этого13.

Выводы

За короткую жизнь Therac-25 было обнаружено два программных дефекта:

  • Логическая ошибка в обновлении параметров, когда оператор менял состояние машины.
  • Проверка безопасности не срабатывала, когда 8-битный счетчик переполнялся и достигал нуля каждые 256 итераций.

Однако с точки зрения безопасности систем самое уязвимое место — это доверие к программному обеспечению. Очевидно, что тот же дефект, который вызвал передозировки в Therac-25, присутствовал и в Therac-20. Та же ошибка в Therac-20 приводила к отключению машины без передозировки, поскольку в Therac-20 применялись независимые аппаратные устройства безопасности, которые предотвращали ее.

Ошибки, связанные с зависимостью от скорости, очень трудно обнаружить и воспроизвести. В первом случае две причины точно должны были присутствовать, чтобы активировать ошибку.

  1. Оператор должен сделать изменения в параметрах режима и уровня энергии.
  2. Оператор должен сделать изменения в течение восьми секунд.

В случае второго дефекта все зависит от случайности. Ошибка активируется, если клавиша нажимается в тот момент, когда счетчик достигает нуля. Вот почему, несмотря на врожденный дефект в продукте, было отмечено только шесть несчастных случаев. Если бы ошибка была более явной и ее было бы легче запустить, несомненно, она была бы выявлена на AECL в ходе обычных процедур тестирования и проверки качества, и тогда о ней никогда не узнало бы общество. Если ошибку трудно активировать, ее также трудно будет выявить в ходе обычного процесса тестирования. Трудно найти ошибки, если не можешь их воспроизвести.

Замечание

    Большинство аварий — аварии системные, то есть они происходят в результате сложных взаимодействий между различными компонентами и процессами. Приписывать аварии какой-либо одной причине — обычно серьезное заблуждение.14

Кроме двух главных ошибок, описанных выше, существовали многочисленные другие, которые мы наблюдали в отношении этой истории и которые, возможно, внесли свой вклад в длительное существование этих главных ошибок.

  • Аппарат Therac-25 имел много неполадок, которые, по-видимому, не причиняли вреда, и операторы научились игнорировать эти капризы. Это напоминает историю о мальчике, который кричал «волк!». Люди научились не обращать на него внимания. Частые отключения и остановки машины беспокоили операторов. Однако операторы никогда не видели никаких вредных последствий для пациентов из-за этих отключений, поэтому они научились игнорировать их. Нечто, что может иметь серьезные последствия, игнорировалось. Постоянные неполадки также демонстрировали внутреннюю нестабильность и небезопасность машины.
  • Когда проявлялась неполадка, Therac-25 выдавал непонятные сообщения, которые не давали обслуживающему персоналу никаких ключей к причинам и следствиям системной ошибки. Конструкция системы не предусматривала адекватной обратной связи, и персонал не мог понять, что происходит. Информация проходила от оператора через программное обеспечение к оборудованию. Когда связь нарушалась, пользователь не имел способов узнать состояние оборудования, поскольку построение программ не позволяло опрашивать оборудование. Ошибка при вводе данных ясно показывает последствия недостатка обратной связи. Например, вместо того, чтобы просто позволить оператору включать пучок лучей после изменения параметров, программы могли быть сделаны так, чтобы облучение не могло начаться до тех пор, пока программа не опросит оборудование о его состоянии и не предоставит эту информацию оператору для проверки.
  • Когда клиники связывались с AECL по поводу потенциальных проблем, фирма не принимала эти проблемы всерьез. Поскольку люди из AECL не могли воспроизвести неисправность, они считали, что проблема не может быть связана с машиной. Более того, поскольку Therac-25 базировался на Therac-20 и Therac-6, машинах, прошедших полевые испытания, они были слишком самоуверенны в отношении потенциального риска. Ошибки были трудны для обнаружения, но, проявив достаточно внимания, их можно было найти. Инциденты в г. Якима 1985 и 1987 годов являются тому яркими примерами. Когда о проблеме впервые сообщили в 1985 году, фирма AECL провела только поверхностное расследование. Она сообщила, что ошибка невоспроизводима и, следовательно, проблемы нет. Однако в 1987 году фирма приняла сообщение всерьез и обнаружила возможную причину некорректного поведения в течение нескольких недель. Как только AECL оказалась готова признать, что ее продукт может содержать дефекты, она оказалась способна взглянуть на проблему с другой точки зрения.
  • Когда была обнаружена ошибка ввода данных, видимо, не было сделано ни единой попытки оценить безопасность системы в целом. В то время поступили сообщения о пяти случаях, а ошибка ввода данных могла объяснить только два из них — случаи в Восточно-техасском онкологическом центре. Первые три передозировки нельзя объяснить этой ошибкой. Это указывает на то, что в системе были другие дефекты, не принятые в расчет, и машина, по-видимому, могла и далее передозировать облучение по другим причинам. Через восемь месяцев произошел второй случай в г. Якима.
  • В Therac-25 было вновь использовано программное обеспечение его предшественников. Повторное использование программ позволило фирме AECL быстрее вывести Therac-25 на рынок, но внушило им ложную самоуверенность по поводу запаса прочности системы. Повторное использование программ приветствуется ведущими специалистами в индустрии в качестве пути к повышению продуктивности и снижению числа дефектов. Это так, но, с другой стороны, это означает, что программные ошибки воспроизводятся. Кроме того, повторное использование создает новые взаимодействия между ранее не связанными компонентами в новом окружении. Эти взаимодействия могут проявить скрытые дефекты и сформировать новые. Дефект, который не проявляет себя в одном случае, может внезапно возникнуть в другой среде. Также, программы обычно плохо документируются, и пользователям трудно понять нюансы повторного использования программных модулей. Массированное использование таких модулей может также привести к неудобному и небезопасному дизайну.

Зарисовка #1

В апреле 2000 года секретный девятистраничный документ НАТО, датированный 23 сентября 1999 года, попал в одну лондонскую издательскую фирму. В ходе Косовского конфликта компьютеры НАТО подвергались атакам со стороны сербов. Ученые НАТО, в поисках путей защиты от дальнейших вирусных атак, создавали вирусы для моделирования различных режимов атаки. Однако эксперимент пошел не так, как планировалось. Экспериментальные вирусы сделали в точности то, что и должны были сделать. Они извлекли документы с жестких дисков инфицированного компьютера и разослали их в качестве невидимых приложений к электронной почте. Так были разосланы секретные документы15.

Ошибка в данном случае представляла собой не вирус, разработанный и реализованный специалистами НАТО. Ошибки были в сетевом окружении и процессе тестирования, которые и позволили разослать секретные материалы. Разве вам не нравится, когда компьютер делает то, что вы от него требуете?

Ошибка в процессоре Intel Pentium

В 1993 году корпорация Intel представила новый процессор Pentium™, который обещал стать самым лучшим процессором на рынке персональных компьютеров в то время. Через год после выпуска профессор Томас Найсели (Thomas Nicely) из Линчбергского колледжа (Lynchburg College) обнаружил ошибку и сообщил о ней в Intel. Это стало совершенным кошмаром для Intel, и в конечном итоге фирма согласилась заменять микросхему автоматически по требованию. Популярная пресса заставила нас поверить, что эта ошибка вызвана глупостью инженеров Intel, — в конце концов, разве трудно проверить каждое значение по справочной таблице? Как обычно, реальность намного сложнее, чем жирные заголовки газетных статей.

История

Профессор Томас Найсели — математик. В период 1993-1994 годов он работал над исследовательским проектом в области, называемой вычислительной теорией чисел (computational number theory). Одной из его целей было продемонстрировать полезность настольных персональных компьютеров. Для своего исследования он заставил большое число персональных компьютеров вычислять простые числа, пары простых чисел, триплеты и квадраплеты простых чисел для всех положительных целых до 6 x 1012. Простые числа — это целые, которые делятся только на единицу и сами на себя (например, 3). Пары простых чисел — это два последовательных нечетных целых, которые также являются простыми (например, 3 и 5). Триплеты простых — это три последовательных целых нечетных простых числа (3, 5, 7). При вычислениях его программа предпринимала некоторое число проверок, в которых уже известные, опубликованные в литературе числа просчитывались, чтобы проверить правильность вычислений. Машина с процессором Pentium приняла участие в вычислениях в марте 1994, а 13 июня 1994 года проверка закончилась неожиданным значением. После четырех месяцев поиска профессор Найсели смог определить ошибку в блоке вычисления чисел с плавающей запятой (floating-point unit, FPU) процессора Pentium. В публичном сообщении, сделанном 9 декабря 1994 года, он описал свои трудности и исследования причины ошибок16.

24 октября 1994 года, после того как профессор окончательно уверился в результатах анализа, он послал в службу технической поддержки Intel сообщение об ошибке. Когда Intel не ответила на сообщение, 30 октября 1994 года профессор Найсели написал письмо некоторым своим коллегам, объявив об открытии ошибки деления чисел с плавающей запятой в процессоре Intel Pentium. В электронном письме он описал свои наблюдения:

Если коротко, FPU процессора Pentium возвращает ошибочное значение для некоторых операций деления. Например,

     1/824633702441,0

вычисляется некорректно (ошибочны все цифры после восьмой значащей цифры)17.

Вскоре сообщение об ошибке уже циркулировало на форуме CompuServe и в группах новостей Интернета. Александр Вулф (Alexander Wolf), репортер EE Times, подхватил эту историю и написал статью, которая появилась в номере EE Times от 7 ноября 1994 года. Отвечая на запрос репортера, Intel заявила, что они обнаружили эту ошибку летом 1994 года, и она была исправлена в процессорах, выпущенных позднее. Однако Intel не смогла определить число выпущенных дефектных процессоров, и они попытались сгладить важность этой ошибки.

Смит (Smith), представитель Intel, подчеркнул, что этот дефект не повлияет на среднего пользователя. Говоря о Найсели, Смит сказал: «Это исключительный пользователь. Он круглосуточно проводит вычисления обратных величин. То, что он обнаружил после многих месяцев вычислений, является примером того, что восемь десятичных чисел правильны и только девятая отображается неверно. То есть ошибка у вас будет только в девятом знаке справа от точки. Я думаю, что, даже если вы инженер, вы этого не заметите».18

CNN распространила это заявление 22 ноября 1994 года, и вскоре оно было во всех главных средствах массовой информации, таких, как New York Times и Associated Press. В других интервью Intel повторяла свое раннее заявление о том, что ошибка несущественна для среднего пользователя.

В среду Intel заявила, что они не считают необходимым отзывать процессор, утверждая, что обычный пользователь имеет только один шанс из девяти миллиардов получить неверный результат из-за этой ошибки и таким образом не будет никаких заметных последствий для компьютеров дома и в офисе. Компания заявляет, что она продолжает поставлять сборщикам компьютеров процессоры Pentium, сделанные до того, как проблема была обнаружена19 .

28 ноября 1994 года Тим Коу (Tim Coe) из компании Vitess Semiconductor опубликовал статью в группе новостей comp.sys.intel, в которой он путем анализа восстановил реализацию алгоритма и предложил модель поведения процессора Pentium. Через несколько дней появились аппаратные и программные «заплатки» для ошибки. 3 декабря 1994 года Воэн Пратт (Vaughan R. Pratt) из Стэндфордского университета опубликовал письмо в группах новостей comp.arch и comp.sys.intel, в котором оспаривал точку зрения Intel о том, что вероятность встречи с ошибкой составляет «один раз в 27 000 лет». Он смог продемонстрировать возможность активации ошибки один раз в каждые 3 миллисекунды в достаточно правдоподобном сценарии. А также он продемонстрировал, что достаточно безобидно выглядящее деление 4,999999/14,999999 приводило к отклонению от правильного результата на 0,00000407 при использовании дефектного процессора20.

12 декабря 1994 года фирма IBM выпустила сообщение, в котором также был подвергнут сомнению анализ Intel о том, что вероятность обнаружения ошибки составляет один к девяти миллионам21.

14 декабря 1994 года Intel опубликовала официальное сообщение, которое было датировано 30 ноября 1994 года22.

В этом сообщении рассматривалась данная ошибка, обсуждались ее последствия, и этот документ был, очевидно, источником многих заявлений Intel. В этом отчете определялось, что вероятность встречи с ошибкой составляет «один к девяти миллиардам» и что среднее время появления ошибки — «один раз в 27 000 лет». Далее Intel описывала причину ошибки и алгоритм работы FPU. Инженеры компании избрали в качестве алгоритма деления процессора SRT алгоритм23 по основанию 4 (radix 4 SRT algorithm), чтобы скорость деления могла быть удвоена, по сравнению с 486-м процессором. Полное описание SRT алгоритма, использованного в процессоре Pentium, находится за рамками этой книги. Детали можно найти в работе Edelman, Sharangpani и Bryant24.

Однако главная причина ошибки в том, что SRT-алгоритм требует справочную таблицу для определения частного. Значение в справочной таблице генерируется численно и загружается в программируемый справочный массив. Дефект скрипта привел к тому, что несколько элементов в справочной таблице были пропущены. Когда выполнялась операция деления, которая требовала эти значения, извлекалось неверное число, и точность вычисленного результата частного оказывалась сниженной.

В конечном счете 20 декабря 1994 года фирма Intel объявила, что она начинает заменять процессоры Pentium по требованию. Это существенно снизило ажиотаж вокруг ошибки в процессоре. Однако это не остановило тех, кто анализировал эту ошибку. 19 сентября 1995 года Алан Эдельман (Alan Edelman) опубликовал отчет, в котором провел детальный анализ этой ошибки25.

В своем отчете он определил, что было только два способа, с помощью которых можно было осуществить доступ к ошибочным данным и использовать их при вычислениях. Ошибочное значение извлекалось, только если делитель содержал шесть последовательных бит, от 5-го до 10-го, установленных в единицу. Таким образом, ошибочные табличные значения могли не извлекаться при тестах, основанных на случайной выборке значения; тест, способный выявить ошибку, должен работать лучше, чем простая случайная выборка. Он также показал, что максимальная абсолютная ошибка в данном случае не могла превышать 0,00005.

Вывод

Ошибка в процессоре Pentium — это ошибка, которую легко совершить, но которую трудно обнаружить в силу двух причин. Во-первых, ошибка в результате операции деления, проведенной дефектным процессором, не превышает 0,00005. Как много из нас придрались бы к различию между 0,33332922 и 0,33333329? Более того, если бы мы использовали эти значения в приложениях, которые автоматически округляют их до двух значащих цифр, мы бы никогда и не узнали о таких небольших различиях. Воэн Пратт писал в своем сообщении:

Эта ошибка наиболее коварна: она почти столь же коварна, как если бы вовсе не вызывала тревоги у людей при просмотре ими колонок своих данных. Таким образом, крошечные ошибки в одну стотысячную могут в течение долгого времени проникать в триллионы вычислений, совершаемых по всему миру, и практически нет способа определить их, кроме как осуществляя массированную проверку на ошибку в FPU, которая совершенно не является необходимой для надежно работающего процессора26.

Вторая причина того, что ошибку трудно найти, состоит в том, что дефект проявляется чрезвычайно редко27.

Шанс того, что неверное значение будет извлечено из справочной таблицы в тестах по случайной выборке, чрезвычайно низок. Intel, используя эти тесты, независимо от других идентифицировала ошибку через год после выпуска процессора. Это ясно говорит о трудностях тестирования и обнаружения этого дефекта.

Для профессора Найсели процесс поиска ошибки начался, поскольку он заметил небольшие несоответствия. Но причина того, что он оказался в состоянии заметить несоответствия, состоит в том, что он поместил операцию проверки вычислений в свой код. Без этих проверок он мог и не заметить проблему так рано, и его вычисления простых чисел могли быть ошибочными. Как только он понял, что проблема существует, он начал систематически убирать ее возможные причины, пока поиск не сузился до FPU процессора Pentium.

Уроков, которые мы можем извлечь за счет Intel, довольно много:

  • Тестирование должно не только следовать спецификации, оно для полноты также должно учитывать использованные алгоритмы.
  • Мы должны использовать в программах средства для постоянного контроля над правильностью программы. Это даст нам возможность найти потенциальные ошибки настолько рано, насколько возможно.
  • Все неожиданные результаты нужно ставить под сомнение и проверять до тех пор, пока мы не объясним их причину. Ошибка может оказаться скрытой.
  • Обнаружение потенциальной фундаментальной причины ошибки — это систематический процесс. Сначала нужно построить гипотезу о возможной причине, а затем проводить эксперименты для ее проверки.
  • Создание упрощенного воспроизводимого опыта может все изменить. Тот факт, что профессор Найсели смог активировать ошибку простой операцией деления, позволил ему протестировать другие системы и конфигурации, что позволило ему опровергнуть неверные гипотезы.

Зарисовка #2

Согласно легенде, ранние конструкции торпед имели устройства безопасности, предохраняющие подводную лодку от повреждения, когда торпеда была запущена. Торпеда была сконструирована так, чтобы самоуничтожение запускалось, если торпеда поворачивалась на 180? . Идея была в том, что повернувшаяся на 180? торпеда может повредить выпустившую ее лодку. Однажды, капитан подводной лодки решил выпустить торпеду. Однако торпеда застряла в пусковой камере, и ее не смогли удалить. Капитан решил вернуться в порт для ремонта. Когда субмарина развернулась на 180 градусов, торпеда взорвалась и потопила лодку.

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

Ariane 5. Ошибка операнда

Если коротко, несчастный случай с Arian 5 был вызван необработанным исключением при преобразовании 64-битного значения с плавающей запятой в 16 битное целое значение со знаком. Значение с плавающей запятой, вызвавшее исключение (или ошибку операнда, как она была названа в официальном сообщении), оказалось больше, чем значение, которое может быть представлено 16 битным целым. Однако более полная версия этой истории гораздо более интересна и поучительна28.

История

Ракета-носитель Ariane 5 была ответом попыткам Европейского космического агентства (European Space Agency) стать лидером в запусках ракет на коммерческом космическом рынке. Стоившая 7 миллиардов долларов и строившаяся в течение 10 лет, Arian 5 могла вывести на орбиту два трехтонных спутника.

При своем первом полете ракета Ariane 5 взорвалась через 40 секунд после старта утром 4 июня 1996 года. Анализ данных полета быстро показал, что ракета вела себя нормально до того момента, когда она вдруг отклонилась от курса и самоуничтожилась. Погода в то утро была приемлемой, так что она не могла оказать влияние. Полетные данные также показывали, что активная система и первичная Инерционная система ориентировки (Inertial Reference System), которые влияли на управление соплами твердотопливного ускорителя, более или менее одновременно отказали прямо перед разрушением ракеты.

После инцидента была сформирована комиссия по его расследованию. Комиссия для решения своей задачи располагала телеметрическими данными ракеты, данными о траектории с радиолокационных станций, оптическими наблюдениями ракеты и упавших обломков и восстановленной Инерционной системой ориентировки. Кроме того, комиссия располагала отдельными компонентами ракеты и системами программ, использованных в ней, для тестирований и осмотра. Получив эту информацию, комиссия смогла реконструировать последовательность событий 4 июня 1996 года.

  1. Программный модуль, в котором в итоге возникла ошибка, был унаследован от ракеты-носителя Arian 4. Этот модуль производил выравнивание инерционной платформы для того, чтобы оценить точность измерений, проведенных Инерционной системой ориентировки. После старта данный модуль более не служил в Ariane 5 никаким целям. Однако в Ariane 4 этот модуль работал в течение еще полных 50 секунд. Начальная часть траектории полета Ariane 5 существенно отличалась от траектории Ariane 4, и этот программный модуль никогда соответствующим образом не тестировался.
  2. Вскоре после старта ошибочный программный модуль попытался посчитать значение, основанное на горизонтальной скорости ракеты. Поскольку для Ariane 5 это значение было существенно больше, чем то, которое ожидалось для Ariane 4, возникла ошибка и на активной, и на запасной Инерционной системе ориентировки. Допустимость такого преобразования не была проверена, поскольку ожидалось, что такого никогда не случится.
  3. Спецификация обработки ошибок в системе указывала, что контекст ошибок должен быть сохранен в постоянной памяти (ПЗУ) до отключения процессора. После ошибки операнда Инерционная система ориентировки сохранила контекст ошибки, как было установлено. Эти данные были прочитаны бортовым компьютером. На основе этих данных компьютер отдал команду соплам твердотопливного ускорителя и главному двигателю. Команда требовала полного отклонения сопел, что вызвало то, что ракета вышла на запредельную траекторию.
  4. На новой траектории ракета подверглась запредельной аэродинамической нагрузке и начала разрушаться. Стартовые двигатели отделились от ракеты, что запустило ее самоуничтожение.

Несомненно, глупая ошибка, но интересен такой вопрос: как эта ошибка миновала стадию тестирования? В аэрокосмической индустрии обычно строгие стандарты и скрупулезные процессы и процедуры, направленные на проверку безопасности из-за высокой цены ошибок. Комиссия по расследованию задала тот же вопрос, и команда обслуживания Ariane 5 представила следующие объяснения:

  • Команда Ariane 5 решила не защищать некоторые переменные от возможной ошибки операнда, поскольку они считали, что значения этих переменных либо ограничены физическими факторами, либо имеют существенный запас по максимальной величине.
  • Команда Ariane 5 решила не включать данные о траектории в функциональные требования для Инерционной системы ориентировки. Следовательно, данные о траектории Ariane 5 не использовались при тестировании.
  • Из-за физических законов трудно осуществить реалистичный полетный тест Инерционной системы ориентировки. При функциональном имитационном тестировании полетных программ было решено не включать в тест эту систему главным образом по той причине, что она должна быть проверена при тестировании аппаратного уровня, а также потому, что было бы трудно достигнуть необходимой точности при имитационном тестировании, если бы была использована реальная Инерционная система ориентировки.
Вывод

Как и в случае других ошибок, которые мы обсуждали, дефект на Ariane 5 не был вызван одной причиной. В ходе всей разработки и процессов тестирования существовало много стадий, на которых данный дефект мог быть выявлен.

  • Программный модуль был повторно использован в новой среде, где условия функционирования отличались от требований программного модуля. Эти требования не были пересмотрены.
  • Система выявила и распознала ошибку. К несчастью, спецификация механизма обработки ошибок была несоответственной и вызвала окончательное разрушение.
  • Ошибочный модуль никогда должным образом не тестировался в новом окружении — ни на уровне оборудования, ни на уровне системной интеграции. Следовательно, ошибочность разработки и реализации не была обнаружена.

Отчет комиссии по расследованию содержит следующее наблюдение, которое мы считаем очень подходящим для всей индустрии программного обеспечения, а не только для разработчиков программ для Ariane 5.

Главной задачей при разработке Ariane 5 является уклон в сторону уменьшения случайной аварии. …Возникшее исключение, объясняется не случайной аварией, но ошибкой конструкции. Исключение было обнаружено, но обработано неверно, поскольку была принята точка зрения, что программу следует рассматривать как правильную, пока не показано обратное. …Комиссия придерживается противоположной точки зрения, что программное обеспечение нужно считать ошибочным, пока использование признанных в настоящее время наилучшими практических методов не продемонстрирует его правильность29.

Однако одна из причин того, что комиссия по расследованию смогла успешно определить виновного, — в сборе данных измерений, в имитационных средах и в документации. Без метеорологических данных было бы трудно исключить влияние погоды. Без телеметрии и полетных данных было бы трудно определить временные параметры изменения траектории и ошибку Инерционной системы ориентации, что позволило комиссии быстро сузить область потенциальных дефектов. Послеполетные имитационные исследования были проведены с использованием реальных данных о траектории полета Ariane 5, и моделирование точно воспроизвело цепь событий, приведших к аварии системы. Комиссия смогла воспроизвести ошибку!

Зарисовка #3

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

Только что услышал сообщение по сетевому радио CBS о том, что футбольные фанаты по всей стране не смогли узнать по Интернету результаты воскресного Суперкубка. Оказалось, что программы-фильтры доступа в Web, установленные на браузерах (например, в некоторых публичных библиотеках), рассматривали «ХХХ» в словах «Суперкубок XXXIV» как ссылку на порносайт30.

В другом примере чрезмерная цензура потенциально оскорбительных слов может сделать вполне безобидное сообщение неразборчивым и забавным. Так Интернет-служба BBC подвергла цензуре такое предложение:

Я надеюсь, вы сохраните пристрастие к острым словечкам, когда я заскочу к вам в класс в субботу в Сканторп, Эссекс. «I hope you still have your appetite for scraps of dickens when I bump into you in class in Scunthorpe, Essex, on Saturday».

Программа превратила его в
«I hope you still have your appetite for s****s of dickens when I ***p into you in class in S****horpe, Es***, on Sa****ay»31, 32

Однако наибольшее раздражение вызывает программное обеспечение, направленное против спама, которое может удалить важные электронные письма, поскольку ошибочно классифицирует их как спам.

Я недавно провел обновление (?) MS Office до MS Office 2000, который среди прочих возможностей позволяет устанавливать более 8 фильтров электронной корреспонденции. Я радостно начал запускать все эти возможности, включая фильтрацию почты. Сюрприз! Я обнаружил, что 8-10 важных сообщений, которые все являлись ответами на запросы, посланные на адреса из личной адресной книги, были перенесены в папку для почты-спама.
Что же случилось? Я участвовал в благотворительной велосипедной гонке, и мне необходимо было сообщить спонсорам, что мне нужны их деньги. Я выслал им электронные письма с просьбой прислать мне чеки. Конечно, это сообщение содержало, по крайней мере, один знак «$», а также, поскольку я возбудимый человек, содержало, по крайней мере, один двойной восклицательный знак «!!». В конце я просил моего респондента выполнить мою гиперболизированную версию его обещания:

>>Марк, ты не обещал мне 5,000$ или что-то около того?

Мы также встретили здесь волшебную фразу «,000». Недавно замечательные люди из Редмонда33 (Redmond) определили, что, если эти три элемента одновременно присутствуют, значит, вы получили спам. Текущее правило (взятое с их Web-сайта) гласит:

Текст содержит «,000» AND текст содержит «!!» AND текст содержит «$»

Кто бы мог подумать? Даже взглянув на список их фильтров, я далеко не сразу понял, какое правило я нарушил (ОК, иногда я медленно соображаю)34.

Это ошибки программы или ошибки пользователя? Во всех трех случаях программное обеспечение функционирует в точности так, как предписывает алгоритм, и производители не посчитали бы эти случаи за ошибки. Однако иногда действие алгоритма — это не то, что хочет конечный пользователь. Поэтому, как конечные пользователи мы выключаем фильтрующее и противоспамное программное обеспечение или же находим пути обойти неверный алгоритм. В главе 3 мы исследуем природу ошибок, что может помочь нам определить точно, что такое ошибка.

Аппарат для исследования климата Марса

Аппарат для исследования климата Марса (Mars Climate Orbiter) является частью программы Mars Surveyor по изучению и картографированию Марса. Ожидалось, что программа Mars Surveyor продлится в течение 10 лет и в рамках программы будет запускаться одна экспедиция в год. Первыми двумя экспедициями были миссии аппаратов Mars Pathfinder и Mars Global Surveyor в 1996 году. Аппарат Mars Climate Orbiter был запущен 11 декабря 1998 года. Следом за ним был также запущен Mars Polar Lander — 3 января 1999. Оба аппарата были потеряны вскоре после того, как они достигли красной планеты. Эти два космических корабля стоили NASA около 327,6 миллиона долларов, потраченных на их создание и функционирование. Эти аварии заставили NASA пересмотреть свои цели и методы в Марсианской программе, чтобы быть уверенными в успехе будущих миссий. Причину аварии Mars Polar Lander определить все еще нельзя. Однако причина потери Mars Climate Orbiter выяснена, поэтому мы сконцентрируем наше исследование на этом аппарате.

История

Mars Climate Orbiter был запущен 11 декабря 1998 года с помощью ракеты-носителя Delta 11 с космодрома на мысе Канаверал (Canaveral) во Флориде. После девяти с половиной месяцев космического полета 23 сентября 1999 года, его планировалось вывести на орбиту вокруг Марса. Однако, когда пришло назначенное время, что-то произошло.

Сегодня, ранним утром, около 2:00 утра по летнему тихоокеанскому времени, аппарат включил главный двигатель для выхода на орбиту вокруг планеты. Вся информация, приходившая до этого момента с борта космического корабля, выглядела нормально. Запуск двигателя начался как планировалось, за пять минут до того, как аппарат оказался за планетой (если смотреть с Земли). Управление полетом не зафиксировало сигнала, когда ожидалось, что аппарат должен был выйти из-за планеты35.

Mars Climate Orbiter разрабатывался объединенной командой инженеров и ученых в двух местах — Лаборатории реактивных двигателей (Jet Propulsion Laboratory, JPL), расположенной в Пасадене (Pasadena), штат Калифорния, и на заводе Lockheed Martin Astronautics, LMA в Денвере, штат Колорадо. Завод LMA был ответственен за планирование и разработку Mars Climate Orbiter с точки зрения интеграции и тестирования полетных систем, а также за операцию запуска. Лаборатория JPL несла ответственность за управление проектом, за управление разработкой космического аппарата и приборов, за системотехнику, за планирование миссии, навигацию, разработку операционной системы миссии, разработку наземной системы сбора данных и гарантии безопасности36.

В ходе девяти с половиной месяцев полета наземные службы отслеживали и сравнивали наблюдаемую траекторию аппарата с расчетной. Также наземные службы проверяли все события, происходящие на борту Mars Climate Orbiter. Одним из таких событий было уменьшение углового момента (Angular Momentum Desaturation, AMD). Событие AMD возникало, когда аппарат запускал двигатели малой тяги для устранения углового момента, накопившегося в его маховиках. В основе своей — это калибровочный маневр для поддержания функционирования системных компонентов в заданном диапазоне. Когда возникало событие AMD, происходила следующая последовательность событий:

  1. Аппарат посылал значимые данные на наземную станцию.
  2. Данные обрабатывались программным модулем, называвшимся SM-FORCE.
  3. Результаты работы модуля SM-FORCE помещались в файл, называемый файл AMD.
  4. Данные файла AMD использовались для вычисления изменения скорости аппарата.
  5. Вычисленное значение изменения скорости использовалось для моделирования траектории корабля.

Согласно спецификации модуль SM-FORCE должен формировать данные, помещаемые в файл AMD, используя метрические единицы, то есть ньютон-секунды. Однако по тем или иным причинам модуль SM-FORCE на наземной станции выводил данные, используя английские единицы (фунт-секунды) (в официальном отчете причина не указывалась, и мы не будем строить предположения по этому поводу). Программный модуль, который рассчитывал изменение скорости с использованием данных из файла AMD, ожидал, что они будут в метрических единицах, согласно спецификации. На борту аппарата модуль, который создавал файл AMD, использовал метрические единицы. Это привело к различию между траекториями, вычисленными космическим аппаратом и наземной станцией, а именно параметры траектории, вычисленные наземной станцией, были в 4,45 раза меньше, поскольку 1 фунт-секунда равен 4,45 ньютон-секундам.

Корабль периодически передавал вычисленную модель траектории на наземную станцию для сравнения. Теоретически быстрое сопоставление моделей, полученных кораблем и наземной станцией, должно было поднять тревогу. Однако несколько осложняющих факторов помешали наземному персоналу осознать ошибку.

  • В программном обеспечении наземной станции было несколько ошибок, и персонал не мог использовать модуль SM-FORCE для расчета траектории корабля. Эти ошибки были исправлены только к четвертому месяцу полета, в районе апреля 1999 года.
  • Персонал, ответственный за навигацию, не знал о том, что данные об изменении скорости с борта корабля были доступны для сравнения в течение долгого времени после запуска.
  • Линия обзора между аппаратом и Землей не давала персоналу точно моделировать траекторию корабля, используя наблюдения.

Если бы событие AMD возникало нечасто, коэффициент 4,45 мог и не иметь таких серьезных последствий. Однако из-за формы корабля это событие возникало в 10-14 раз чаще, чем ожидалось. Более того, когда были обнаружены различия в моделях наземной станции, космического корабля и данных наблюдений, неофициальный отчет об этих различиях был отправлен по электронной почте, без использования стандартной процедуры для таких случаев. В конечном итоге эти различия не были устранены до потери космического аппарата.

8 сентября 1999 года персонал наземной станции рассчитал маневр для вывода корабля на орбиту Марса. Это вычисление было сделано с использованием неверной модели. Целью этого маневра была коррекция траектории корабля таким образом, чтобы точка наибольшего приближения к Марсу составляла 226 километров. 23 сентября маневр был выполнен. Запуск двигателя произошел в 09:00:46 по Всемирному координированному времени (UTC), более известному как время по Гринвичу (GMT). Спустя четыре минуты и шесть секунд наземная станция потеряла сигнал с аппарата. Потеря сигнала была вызвана тем, что Orbiter находился за планетой. Но это событие произошло на 49 секунд раньше, чем было предсказано моделью траектории. Поскольку была использована ошибочная модель траектории, корабль оказался в действительности ближе к поверхности планеты, чем ожидалось. Действительная точка максимального сближения оказалась приблизительно 57 километров. По оценке, такая высота оказалась слишком мала для аппарата.

Вывод

«Люди иногда делают ошибки», — заявил доктор Эдвард Уэйлер (Edward Weiler), первый заместитель главы NASA по науке о космосе. «Данная проблема — это не ошибка, это неудача системотехники и систем проверки в наших технологиях, предназначенных для обнаружения ошибки. Вот почему мы потеряли космический аппарат»37.

Одна ошибка была допущена в одной из частей программного обеспечения. Однако целая серия ошибок на протяжении девяти с половиной месяцев полета привела в конечном итоге к потере аппарата. Назвать первоначальную ошибку фундаментальной причиной аварии мешает тот факт, что данный инцидент не был результатом только одной ошибки. Вот три главных составляющих аварии Mars Climate Orbiter:

  • Если бы было проведено соответствующее тестирование, такая ошибка могла быть быстро обнаружена и исправлена.
  • Однако, поскольку программное обеспечение наземной станции не было хорошо протестировано, после запуска космического аппарата проявились дополнительные ошибки. Эти ошибки отсрочили наблюдения над проблемой. Вместо девяти месяцев из-за дополнительных ошибок персонал имел только пять месяцев на выяснение причины несоответствий.
  • Когда несоответствие в итоге было обнаружено, оно так и не было правильно объяснено. Первоначальная причина так и не была выяснена, а это дало бы персоналу информацию о надвигающейся катастрофе.

В отчете комиссии по расследованию первой фазы ее работы также были указаны следующие факторы неудачи и сделаны некоторые дополнительные рекомендации38. Эти факторы и рекомендации главным образом касаются методов и технологий проекта, которые могли быть полезны для программного обеспечения наземных служб.

  • Обмен информацией. — Обмен информацией является главной проблемой в проекте большого масштаба, программном или любом другом. В случае с Mars Climate Orbiter команды, работавшие над проектами, не связывались действенным образом друг с другом. Команда наземного обслуживания не сообщала о своем беспокойстве по поводу различия траекторий команде управления космическим аппаратом и органам управления проектом. Важная информация от одной команды не передавалась другим командам, что внесло свой вклад в аварию.
  • Обучение и переход от стадии разработки к стадии функционирования. — Одна из причин того, что различия в моделях траекторий так и не были полностью объяснены, пока не случилась катастрофа, состоит в том, что обслуживающий персонал не был полностью обучен. Переход от разработки к функционированию не был тщательно спланирован и осуществлен. В разработке программного обеспечения это можно приравнять к тому, как если бы команда разработчиков перебросила готовую систему команде сетевых операторов, не снабдив их соответствующими инструментами и не проведя обучение особенностям и поведению системы.
  • Проанализируй, что может выйти из строя. — Исследователи считают, что предварительный анализ критических условий системы может помочь предотвратить будущие аварии. Это сходно с анализом отказоустойчивости, анализом процедур восстановления после ошибки и планированием нагрузки, проводимым в распределенных компьютерных средах, обычно встречающихся в системе Интернета.
  • Самоуверенность. — Комиссия по расследованию обнаружила, что персонал проекта считал посылку космического аппарата на орбиту вокруг Марса легкой задачей, поскольку JPL имела тридцатилетний опыт безошибочной межпланетной навигации. Эта самоуверенность может объяснить недостаток соответствующего тестирования в программных модулях.

Зарисовка #4

Этот инцидент не связан с какой-либо программной ошибкой. В действительности в этой истории программное обеспечение не участвует вовсе. Однако эта история поучительна и забавна и заслуживает места в этой главе. Это укороченная версия истории, в которой описывается субподрядчик, который выполнял работу по прокладке волоконно-оптического кабеля для одной местной телефонной компании. Перед описываемым инцидентом субподрядчик отключил телефонную линию и воспользовался машиной-канавокопателем для прорытия канавы в земле. Однако земля была мокрой от утренней росы, и канавокопатель соскользнул по откосу дороги и столкнул субподрядчика в яму глубиной 10-15 футов. Человек, заметивший этот несчастный случай, подъехал к ближайшему дому, чтобы вызвать по телефону помощь, но телефон не работал. Почему? Потому что телефонная линия была отключена субподрядчиком для проведения работы. Что еще более курьезно, в машине субподрядчика был сотовый телефон, но товарищи раненого по работе совершенно забыли о нем в момент инцидента. В конце концов другой свидетель смог позвонить в службу спасения из другого дома, и инцидент закончился благополучно. Пострадавший был отправлен в больницу без серьезных повреждений. Канавокопатель извлекли из ямы, и общество получило волоконно-оптические кабели39.

Какой урок мы можем извлечь из этого инцидента, который можно было бы применить к наладке программного обеспечения? Главный вывод — всегда имейте резервную копию. Часто в азарте исправления и изменения кода мы чувствуем такую уверенность в своих изменениях, что принимаем их без должного тестирования. Принятые изменения — это такие модификации, которые трудно вернуть в первоначальное состояние, и мы оказываемся в тупике, если возникает проблема. Это напоминает историю с субподрядчиком, который отключил телефонную линию, не подумав о возможности того, что что-то может случиться, и, когда это действительно случилось, он остался без телефона.

Создание резервной копии кода, комментирование40 кода при его замене вместо удаления, создание копии старой функции с другим именем и использование инструментов управления конфигурацией — вот некоторые советы, которые вы можете использовать, чтобы сохранять пути отступления до того, как вы серьезно протестируете ваши изменения. Однако эти пути бесполезны, если вы не помните, что они у вас есть. В описанной истории помощь могла быть вызвана раньше, если бы кто-нибудь вспомнил о сотовом телефоне в машине. В нашей работе опасность не в том, что мы забудем, что у нас есть путь отступления, а в попытках определить, какая версия старого кода (или какая комбинация версий из разных модулей) соответствует последней работающей версии системы.

Авария на телефонной компании AT&T

Для большинства из нас авария на телефонной станции означает то, что мы не можем пользоваться телефонами: не можем звонить сами, и люди не могут звонить нам. Аварии — это ожидаемый и принимаемый риск в этой индустрии. Ураганы могут повредить телефонные линии, подземные кабели могут быть повреждены из-за человеческой ошибки или землетрясения или же возможны ошибки в программном обеспечении, которое управляет сетью.

К 15 января 1990 года в компании AT&T произошла авария, охватившая всю страну и продолжавшаяся девять часов. Причина состояла в ошибке в программном обеспечении, которое должно было сделать эту систему более эффективной. Восемь лет спустя, 13 апреля 1998 года, на AT&T произошла другая крупная авария в сети ретрансляции кадров (frame relay network), которая затронула банкоматы, операции с кредитными картами и другие службы, связанные с передачей бизнес-данных. Авария длилась 26 часов. И опять ошибка была внесена при обновлении программного обеспечения.

Сделала ли AT&T одну и ту же ошибку дважды или здесь было что-то еще?

История: авария 1990 года

В 1990 году телефонная сеть AT&T состояла из 114 соединенных между собой систем коммутирования вызовов 4ESS (4ESS toll switching systems) (это представление является упрощением). Для нашего обсуждения мы мысленно смоделируем сеть AT&T в виде схемы. В этой схеме существует 114 узлов (точек пересечения) и каждый узел представляет один из 114 коммутаторов 4ESS. Линии, нарисованные между узлами, изображают коммуникационные каналы между ними.

В такой телефонной сети, когда один из узлов сталкивается с проблемой, он посылает сообщение «не беспокоить» всем узлам, с которыми он соединен. Это сообщение информирует соседний узел о том, что данный узел не может обрабатывать новые вызовы и просит соседний узел считать его не работающим. Тем временем аварийный узел активирует процесс восстановления после сбоя, который длится от четырех до шести секунд. По окончании процесса восстановления аварийный узел посылает сообщение, известное как Начальное адресное сообщение (Initial Address Message, IAM), всем соседним узлам, сообщая им о своем новом статусе и требуя направлять вызовы на восстановленный узел.

В середине декабря 1989 года AT&T произвела обновление программного обеспечения на коммутаторах 4ESS с целью увеличения производительности системы и введения быстрого процесса восстановления после ошибки. Приблизительно в 2:30 по Восточному стандартному времени (EST) 15 января 1990 года на 4ESS коммутаторе в Нью-Йорке возникла небольшая аппаратная проблема, и коммутатор начал процесс восстановления, как было описано выше. После того как Нью-Йоркский коммутатор исправил проблему, он послал сообщение IAM для уведомления соседних коммутаторов, что он готов продолжать работу. Однако обновление программ, проведенное в середине декабря, внесло в действия ошибку. Эта ошибка проявилась, когда коммутатор получил два IAM сообщения с интервалом 1/100 секунды. Некоторые данные в коммутаторе оказались искажены, и он прекратил обслуживание, перейдя к инициализации. Когда соседние узлы выходили из строя, они запускали тот же самый процесс восстановления. Поскольку все коммутаторы были одинаковы, та же последовательность событий каскадом распространялась от одного коммутатора к другому и вывела из строя всю систему.

В течение дня инженеры AT&T смогли стабилизировать сеть, уменьшив нагрузку на нее. К 23:30 EST они смогли очистить все звенья сети, и система практически вернулась к нормальному состоянию.

Во вторник, 16 января 1990 года, инженеры AT&T смогли идентифицировать и выделить ошибку, которая была отслежена до набора ошибочных кодов. Этот код активировался в ходе процедуры восстановления коммутатора. Отрывок кода, который вызвал аварию, представлен ниже41:


1.do {
2. ...
3. switch (expression){
4. case (value 0):{
5. if (logical_test){
6. ...
7. break;
8. }else {
9. ...
10. }
11. ...
12. break;
13.} 
14. ...
15. }
16. ...
17. }while (expression); 

В данном случае виновным оказался оператор break в строке 7. Согласно реализации, если logical_test прошел успешно, программа переходит к строке 6 для выполнения расположенных там операторов. Когда выполнение программы доходит до строки 7, оператор break заставляет программу покинуть блок оператора switch, расположенного между 3 и 15 строками, и исполнять код начиная со строки 16. Однако эта часть исполнения не входила в намерения программиста. Программист желал, чтобы оператор break в седьмой строке прерывал выполнение условного оператора if-then и чтобы после исполнения седьмой строки исполнение продолжилось со строки 11. В таблице 2.1 показаны различия в исполнении программы, как это было задумано и как это было реализовано.

Таблица 2.1. Желаемые и реализованные последовательности инструкций, которые привели к аварии в телефонной сети AT&T 1990 года

ход выполнения реализация ожидалось
шаг 1 строка 2 строка 2
шаг 2 строка 3 строка 3
шаг 3 строка 4 строка 4
шаг 4 строка 5 строка 5
шаг 5 строка 6 строка 6
шаг 6 строка 7 строка 7
шаг 7 строка 16 строка 11 (не верно)
шаг 8 строка 17 строка 12 (не верно)
шаг 9 строка 16 (не верно)
Вывод: авария 1990 года

Программная ошибка, приведшая к аварии 1990 года, — это типичная ошибка новичка. Но ошибки делаем все мы, и даже ветеран с 20-летним стажем может совершить случайно глупую ошибку. Если ошибки неизбежны, вопрос состоит в том, что мы можем сделать для того, чтобы отыскать ошибку до того, как она станет достоянием общества? У нас нет никакого знания из первых рук о внутренней кухне разработки программ в AT&T в 1990 году. Следовательно, мы не можем оценить вклад других причин. В официальном отчете AT&T говорилось:

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

Мы не считаем возможным обвинять в аварии 1990 года процесс разработки программного обеспечения в AT&T и не имеем оснований считать, что AT&T не протестировала тщательно обновление для своих программ. Оглядываясь назад, легко говорить, что, если бы разработчики только протестировали свои программы, они сразу увидели бы эту ошибку. Или то, что, если бы они проверили код, они, возможно, обнаружили бы дефект. Проверка кода может быть и помогла бы в данном случае. Однако единственный случай, когда проверка кода помогла бы найти данную ошибку, если бы другой специалист увидел именно эту строку кода и спросил первого программиста, входил ли этот код в его (ее) намерения. А единственная причина, по которой этот специалист мог бы задать такой вопрос, — знакомство со спецификацией к этому конкретному блоку кода.

Ошибки такого рода обычно нелегко выявить при тестировании в обычной тестовой среде. Такую ошибку можно воспроизвести, как только вы поймете ее и создадите последовательность действий для ее активации. Однако шанс создать правильную последовательность событий случайным образом очень мал, особенно если система будет использоваться в крупномасштабной среде реального времени, которую трудно имитировать в лабораторных условиях. Более того, новое программное обеспечение работало правильно примерно в течение месяца, что соответствует нескольким миллиардам обработанных вызовов. В программном обеспечении был дефект, но этот дефект требовал целого набора специфических событий и факторов, для того чтобы пробудиться к жизни.

  • Эта ошибка требовала, чтобы нагрузка на сеть была продолжительной. Когда нагрузка на сеть уменьшалась, действие дефекта, по существу, исчезало43.
  • Эта ошибка зависела от временных параметров. Чтобы ошибка активировалась, было необходимо, чтобы были получены два IAM сообщения от одного и того же коммутатора с интервалом менее 10 миллисекунд.
  • Тот факт, что на всех коммутаторах было установлено одинаковое программное обеспечение, делал систему расширяемой. Однако был риск в том, что, если на всех коммутаторах был один и тот же дефект, они все оказывались чувствительными к одной и той же ошибке.
    История: авария 1998 года

    13 апреля 1998 года в 2:30 после полудня к коммутатору системы ретрансляции кадров Cisco Stratacom BPX был направлен техник для обновления транк-карты (trunk-card)44. Коммутатор Stratacom BPX содержал две транк-карты, одна из которых была активной, тогда как другая находилась в ждущем режиме и выполняла функцию резерва. Фирма AT&T использовала две процедуры обновления транк-карт. Одна процедура использовалась, если коммутатор был в текущее время подключен к сети и активен, тогда как другая процедура применялась, если коммутатор был изолирован, то есть не соединен с сетью.

    Согласно первому сценарию, то есть когда коммутатор считался активным, процедура требовала, чтобы техник заменил сначала карту, находящуюся в ждущем режиме. Как только становилось ясно, что состояние новой карты стабильно, старая активная карта переводилась в ждущий режим, а новая карта становилась активной. Проведя эту операцию, техник мог заменить оставшуюся карту (теперь находящуюся в ждущем режиме). При второй процедуре предполагалось, что коммутатор отключен от сети и техник мог менять обе карты одновременно.

    Когда техник прибыл на место, он посчитал, что коммутатор, которому требуется обновление, не подключен к сети, поскольку казалось, что через него не проходил никакой сетевой трафик. Однако коммутатор был подключен к сети и активен. К несчастью для техника и для AT&T, обе карты имели дефекты. Как только карты были установлены и активированы, они немедленно выслали коммутатору поток сообщений об ошибках. Эти сообщения от транк-карт активировали ошибку в программном модуле коммутатора. Этот дефект вызвал распространение передачи сообщений об ошибках к другим коммутаторам сети, ко всем 145. Объем этих посланий был достаточно велик, для того чтобы быстро перегрузить все коммутаторы, что очень действенно вывело из строя всю систему приблизительно к 3:00 пополудни45.

    Информации об ошибках в программном обеспечении транк-карт и коммутатора Cisco немного. Элка Ярвис (Alka Jarvis), менеджер по программному обеспечению Cisco Systems, 28 мая 1998 года на заседании сессии Международной недели качества программного обеспечения (International Software Quality Week) прокомментировал, что код, который вызвал аварию в сети AT&T, являлся наследством прошлого46.

    Компания AT&T смогла быстро изолировать аварийный коммутатор, к 23:00 он был отключен от сети. Оставшаяся задача состояла в том, чтобы просто перестроить всю сеть, одну часть за другой. К 2:00 пополудни 14 апреля 1998 года 99,9 % сети ретрансляции кадров были снова работоспособны. Однако определение причины аварии заняло у AT&T около недели, и 22 апреля 1998 года фирма выпустила отчет, очерчивающий причину выхода сети из строя.

    Вывод: авария 1998 года

    Хотя в аварии 1998 года и участвовало программное обеспечение, существует множество причин, внесших свой вклад в данное происшествие. Эта авария отличалась от аварии 1990 года тем, что процедурная ошибка в ходе обновления запустила скрытые программные дефекты. Однако сходств очень много.

    • Установка нового программного обеспечения запустила ошибку. Программы, и старые и новые, имели многочисленные скрытые дефекты, которые не были обнаружены в ходе обычных тестовых процедур. Наличие скрытых дефектов изменило функциональную среду и запустило дефект, вызвавший аварию.
    • Ошибочный код не был проверен должным образом. При аварии 1990 года это был новый код от AT&T. При аварии 1998 года — старый код от Cisco Systems.
    • Программные дефекты в обоих случаях представляли собой проблемы со скрытыми граничными условиями, которые было трудно протестировать и которые, по всей вероятности, так и не были протестированы.

    Авария 1998 года в сети AT&T выявила многочисленные просчеты в процедурах и процессах обслуживания сети и продемонстрировала трудности в разработке и поддержании в рабочем состоянии надежной сети. Очевидно, AT&T извлекла урок из своих ошибок и исправила многочисленные процедурные и функциональные недостатки и ввела многочисленные планы для восстановления после аварий, чтобы минимизировать риск другой общесистемной аварии47.

    Переполнение буфера

    18 июля 2000 года через список рассылки BugTraq было опубликовано детальное описание уязвимости систем безопасности Microsoft Outlook и Outlook Express. BugTruq — это список рассылки (mailing list), посвященный обсуждению компьютерной безопасности. Указанная уязвимость, по существу, обеспечивается ошибкой, обычно называемой в программной индустрии переполнение буфера (buffer overflow). В наиболее простой форме переполнение буфера случается, когда программа старается поместить данные в область памяти, которая слишком мала для их хранения. Следующий отрывок кода представляет собой пример на языке С:

    
    1. char Array[10];
    2. strcpy (Array, "Это вызовет переполнение буфера");
    

    Размер массива составляет 10 символов, а сообщение: «Это вызовет переполнение буфера» состоит из 31 символа. Функция strcpy() пытается скопировать 31 символ в область, размеры которой позволяют хранить только 10 символов, и, таким образом, часть сообщения пишется за пределами разрешенной области. Когда такое случается, программа иногда претерпевает сбой. В другой раз программа может продолжать работу в течение некоторого времени без побочных эффектов. Но если сообщение составлено подходящим образом, это может привести к выполнению встроенного в сообщение «вируса», что вызовет заражение компьютера этим вирусом.

    До настоящего момента наибольшую заботу о безопасности компьютера вызывали многообразные вирусы, которые требовали от пользователей предпринять некоторые действия для осуществления заражения. К таким вирусам относятся такие, как «ILOVEYOU» в 1999 году и «Melissa» в 1998 году. В обоих случаях для активации вируса пользователя хитростью заставляли запустить программу или открыть файл. Однако ошибка переполнения буфера в Outlook не требует вмешательства конечного пользователя. Для того чтобы вы подверглись атаке, достаточно просто получить электронное письмо, и это делает атаку особенно трудной для отражения.

    В отличие от прочих случаев, описанных в этой главе, эта ошибка не ограничивается программой Microsoft Outlook. Как ошибка, переполнение буфера существует последние 10 лет, и это хорошо известное уязвимое место систем безопасности. Вне пределов проблем безопасности сетей переполнение буфера также очень распространенная ошибка — вероятно, каждый создавал такой дефект в какой-то момент своей карьеры. Когда бы вы использовали переменную фиксированного размера, такую, как массив, вы рискуете создать ошибку переполнения буфера. Поскольку эта проблема так распространена, вместо того чтобы детально описывать ошибку в Microsoft Outlook, мы поговорим об ошибке переполнения буфера вообще — как эта ошибка создается, какого рода риск для безопасности она может представлять и что мы можем сделать, чтобы избежать ее.

    История

    Причину переполнения буфера понять легко. Оно происходит, когда мы пытаемся записать слишком много данных в фиксированную область памяти (буфер). Чтобы понять, как переполнение буфера может вызвать сбой программы или стать уязвимым местом в системе безопасности, мы должны проникнуть во внутреннюю логику работы компьютера.

    Когда вы пишете программу на языке высокого уровня, таком, как С, компилятор переводит программу в машинный код. Машинный код, по существу, представляет собой последовательность инструкций низкого уровня и данных. Например, рассмотрим следующую основную программу:

    
    1.main(){
    2.printf("Hello World");
    3.}
    

    Знаменитая программа «Здравствуй, мир» создает 300 294 байта исполняемого кода при использовании компилятора ‘С’ GNU (GCC) в Windows NT, и это выглядит примерно так:

    
    0x401000 55 89 e5 83 ec 10 83 3d 00 20 40 00 00 74 01 cc
    0x401010 d9 7d fe 66 8b 45 fe 25 c0 f0 ff ff 66 89 45 fe
    …
    0x401040 48 65 6c 6c 6f 20 57 6f 72 6c 64 00 55 89 55 89
    0x401050 e5 e8 94 01 00 00 68 40 10 40 00 e8 92 01 00 00
    0x401060 83 c4 …
    

    Что-то довольно непонятное, не так ли? Эти числа — это то, что компьютер использует, когда исполняет написанную вами программу. Числа в этом коде представлены в шестнадцатеричном виде. Первая колонка представляет собой адрес памяти, где находится программа, а оставшиеся колонки показывают содержимое этих адресов памяти. Каждая колонка увеличивает значение адреса на единицу. Таким образом, по адресу 401000 хранится значение 55, по адресу 401001 хранится значение 89 и так далее. Некоторые из этих чисел — команды, которые говорят компьютеру, что делать, другие представляют собой данные, используемые компьютером. В данном случае компьютер берет первое значение, 55, и интерпретирует его как команду выполнить некоторое действие. Затем он переходит к следующему значению — 89. Компьютер знает, что команда 89 требует параметр, который хранится в следующем адресе и имеет значение е5. Таким образом, компьютер выполняет команду 89 е5 и затем переходит к значению, идущему следом за е5. Так компьютер исполняет эти команды по одной за раз. В программе «Здравствуй, мир» строка «Hello, world» представляет собой данные. Если вы можете прочитать шестнадцатеричные значения и знаете коды ASCII, вы можете увидеть, что строка «Hello, world» расположена по адресу 0х401040.

    
    0x401040 
    48(H)65(e)6c(l)6c(l)6f(o)20()57(W)6f(o)72(r)6c(l)64(d)00
    

    Этот набор чисел выглядит совершенно неотличимым от другого набора чисел. Что же не дает компьютеру рассматривать эти числа, как последовательность команд? Ничего, кроме логики, реализованной в программе и которая является главной проблемой при ошибке переполнения буфера. Если вы совершаете ошибку, компьютер считает эти данные командами и исполняет их как таковые. У него нет способа узнать, что эти значения относятся к данным. Такие команды бессмысленны, и программа, наиболее вероятно, остановится. Таким образом, задача потенциального нарушителя — использовать эту ошибку, чтобы заставить компьютер исполнять те данные, которые он ему предоставит. Следовательно, нарушители, которые хотят атаковать ваш компьютер с помощью ваших программ, должны сделать две вещи:

    1. Вставить свой код в память.
    2. Заставить компьютер исполнять этот код.

    Ошибка переполнения буфера дает хакеру возможность сделать и то и другое. Поскольку программа не проверяет размер буфера, когда пишет в него, нарушитель может поместить произвольное содержимое в область памяти, идущую за буфером, — и сражение наполовину выиграно. Вторая половина будет выиграна, когда потенциальный хакер определит, как можно заставить компьютер выполнить код, который он вставил в вашу программу48.

    Вывод

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

    • Не помогают языки программирования. Ошибки переполнения буфера приобрели характер эпидемии в тех языках, в которых нет встроенных средств проверки границ, таких, как С и С++. Эти языки дают программистам возможность манипулировать компьютером произвольно. Эта сила доверяется программистам, и от них ждут, что они будут программировать корректно и безопасно. Ожидается также, что они будут проводить явные проверки границ, если это необходимо. С другой стороны, такие языки, как Java, проводят явные проверки границ, и вероятность того, что ошибка переполнения буфера может быть использована, очень низка. Однако язык Java ограничивает возможности программиста. Он отнимает у него возможность напрямую манипулировать пространством памяти машины. Нельзя сказать, что переполнение буфера невозможно в программе на Java. Это просто означает, что программист должен внести серьезные искажения, чтобы вызвать переполнение буфера на Java. Когда это случается, определить причину крайне тяжело. И поскольку большая часть виртуальной машины Java написана на С и С++, всегда существует опасность ошибки переполнения буфера в виртуальной машине Java.
    • Программистам нельзя доверять. Программисты — люди, а люди делают ошибки. Я по невнимательности много раз за свою жизнь создавал ошибки переполнения буфера. Много раз ошибки возникали, поскольку я создавал макет программного модуля и проверка границ массивов — это последнее, о чем я думал. Но макет имеет обыкновение находить способ проникать в продукт. В другой раз ошибки возникали, потому что я делал допущения по поводу кода и процесса функционирования и считал, что переполнение буфера невозможно. Как это обычно бывает, как только я делаю какие-либо допущения, что-нибудь показывает мне мою неправоту. Часто ошибки появляются из-за моей лени. Написание кода проверки на переполнение буфера — задача в большинстве случаев легкая, но обработка условий обнаружения нарушений границ может оказаться трудным и надоедливым делом. Могу ли я просто прервать выполнение программы? Или я должен сообщить об ошибке вызываемой функции? Как эта функция будет обрабатывать эту ошибку? Прерываю ли я выполнение программы в вызываемой функции до бесконечности? Проще всего не иметь с этим дела и допустить, что такого не случится. Я займусь этим, если те, кто тестируют программы, докажут, что я не прав.
    • Языковые конструкции делают это сложным. Проведение проверки границ в некоторых языках может оказаться трудным делом — на ум приходит использование функции sprintf(). Поскольку sprintf() принимает переменное число аргументов, при использовании этих аргументов от программиста требуется посчитать размеры буфера. Это может легко вызвать переполнение, поскольку вы не понимаете нюансов языка. В С и С++ строка «Hello World» требует 12 символов памяти, потому что язык определяет, что строка должна оканчиваться символом с кодом «0». Иными словами, код «0» добавляется в строке после символа «d». Если вы выделили буфер размером в 11 символов, считая, что он вместит в себя всю строку, то использование любых строковых функций, таких, как strcpy(), приведет к ошибке переполнения буфера, и это ударит по вам, когда вы меньше всего ожидаете.

    Легко говорить о способах окончательного избавления от ошибок переполнения буфера. Например, прекратите использовать небезопасные языки, такие, как С и С++, и приучите себя писать программы с позиций «оборонительного программирования»49. Мы понимаем, что это легче сказать, чем сделать. Если мы примем то, что ошибка переполнения буфера неизбежна, и то, что нам необходимо использовать небезопасные языки программирования, тогда единственным решением будет поиск ошибки. Чем раньше мы обнаружим ошибку, тем меньше шанс, что она огорчит нас в будущем.

    С точки зрения безопасности ошибка не беспокоит нас, если программа зависает, но беспокоит, если ее можно использовать. Теперь сделаем ударение на том как предотвратить ошибку переполнения буфера от использования злоумышленником. Есть многочисленные исследовательские проекты и коммерческие продукты, касающиеся этой темы, и мы считаем, что читателям нужно ознакомиться с этими документами для получения дальнейшей информации50.

    Заключение

    Ошибки, обсуждаемые в этой главе, за несколькими исключениями, существовали или существуют в настоящее время. Сейчас тысячи разработчиков программ устраняют ошибки, работая сверхурочно. Некоторые из этих ошибок забавны, тогда как другие — подлые или трагичные. Тем не менее это совсем не забавно, если вы — один из тех, кто работает по выходным, устраняя ошибки. Однако цена, которую платят разработчики программ, мизерна по сравнению с последствиями этих ошибок. В этой главе мы узнали, что цена ошибки может быть астрономической. Миллионы долларов, затраченные на оборудование и работу, исчезают без следа. Человеческая боль и страдания, даже смерть могут быть вызваны простой ошибкой в программе.

    Мы узнали, что, несмотря на все тестирование, технологии и процедуры, ошибки неизбежны. И сбои, проявляющиеся в конечном продукте, как правило, являются результатом целой серии ошибок. Обычно не существует какой-то одной причины. Вместо этого есть целая коллекция причин, предотвращающих обнаружение и удаление ошибки до рокового финала. Например, простая ошибка программирования привела к аварии на AT&T в 1990 году. Однако, если бы был проведен тест по исполнению кода в ошибочной его части, дефект был бы выявлен раньше, и это спасло бы AT&T от аварии телефонной сети общенациональных масштабов. Является ли главной причиной ошибки программист, написавший неверный код, или отдел тестирования, который позволил дефекту проникнуть в код конечного продукта?

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

    Мы определили много причин тех ошибок, о которых рассказано в этой главе. Эти причины кратко перечислены и обобщены ниже.

    • Недостаток понимания инструментов и конструкций языка:
      • Случаи — авария 1990 года на AT&T, ошибка переполнения буфера.
      • Описание — дефект возникает, когда программист неправильно понимает конструкции языка. При аварии на AT&T 1990 года ошибка заключалась в неверном расположении оператора break. Типичная ошибка переполнения буфера может быть вызвана непониманием средств манипуляции со строками в стандартных функциях С и С++.
    • Повторное использование модулей без понимания:
      • Случай — Ariane-5.
      • Описание — унаследованный программный модуль был использован повторно, но наблюдался недостаток понимания требований этого модуля. Не было сделано попыток оценить правомерность использования.
    • Изменения и обновления программ:
      • Случаи — аварии на AT&T 1990 и 1998 годов.
      • Описание — ошибка проявилась в ходе и после окончания обновления программ, которое было направлено на повышение производительности системы.
    • Игнорирование неожиданных результатов:
      • Случаи — Mars Climate Orbiter, Therac-25.
      • Описание — в обоих случаях была масса предупреждений и подсказок из различных источников о том, что что-то не так. Предупреждения проявлялись как неожиданные результаты и поведение. Но эти предупреждения регулярно игнорировались, и должное расследование не было проведено. В случае Mars Climate Orbiter проблема состояла в несовпадении между рассчитанными моделями с борта космического корабля и с наземной станции. В случае с Therac-25 проблема была в постоянных неполадках и Therac-20, и Therac-25.
    • Непонимание подсказок:
      • Случаи — Mars Climate Orbiter, Therac-25, Компания Х, Компания Y.
      • Описание — ключи, указывающие на потенциальные ошибки, не интерпретировались корректно, что в конечном счете привело ко всем описанным авариям. И в случае с Компанией Х, и в случае с Компанией Y подсказки прекрасно описывали причину симптомов, но эти подсказки первоначально не были приняты во внимание.
    • Недостаток подходящих средств мониторинга:
      • Случаи — Mars Climate Orbiter, Therac-25, Компания Х, Компания Y.
      • Описание — хорошие средства мониторинга могут помочь обслуживающему персоналу обнаружить и решить проблему до того, как она приобретет серьезные последствия. Может быть, несправедливо относить в эту категорию Mars Climate Orbiter, поскольку ученые были ограничены технологиями и законами физики в том, что они могли наблюдать. Тот факт, что они не могли наблюдать действительную траекторию космического аппарата, ограничивал их возможности в определении правильности их модели. В случае Therac-25 сообщения об ошибках не имели достаточно описательного характера, чтобы встревожить операторов потенциальными проблемами в машине. Так же наблюдался явный недостаток обратной связи, позволяющей оператору точно знать, что делает машина. Проблемы в Компаниях Х и Y могли бы быть минимизированы, если бы обслуживающий персонал смог определить падение производительности базы данных до аварии.
    • Неверная или бедная спецификация:
      • Случай — Ariane 5.
      • Описание — спецификация обработки ошибки определяла, чтобы ошибочное значение было помещено в память, используемую навигационным компьютером. Реализация программного обеспечения точно соответствовала спецификации. Навигационный компьютер использовал это значение для осуществления маневра с использованием двигателей, что вызвало катастрофу. В данном случае спецификация обработки ошибки была ошибочна и вызвала крушение.
    • Отклонение от спецификации:
      • Случай — Mars Climate Orbiter.
      • Описание — спецификация для Mars Climate Orbiter была очень ясной: единицы измерения должны быть метрическими, а не английскими.
    • Унаследованные ошибки:
      • Случаи — Therac-25, авария на AT&T 1998 года.
      • Описание — унаследованные программные модули содержали ошибки, которые не были обнаружены в их предыдущем воплощении.
    • Отклонение от должной процедуры:
      • Случаи — авария на AT&T 1998 года, компания Х.
      • Описание — процедуры были разработаны для того, чтобы помешать нам сделать ошибку, а когда процедуре не следуют, а идут коротким путем, возникают нежелательные эффекты.
    • Небезопасные средства:
      • Случай — переполнение буфера.
      • Описание — одной из главных причин ошибки переполнения буфера является «небезопасность» таких программных языков, как С и С++, в которых программа зависит от того, провел ли программист явную проверку границ массивов для предотвращения этих ошибок.
    • Человеческий фактор:
      • Случай — переполнение буфера.
      • Описание — мы все знаем, как предотвращать ошибки, и все же мы продолжаем их делать.
    • Эго и самоуверенность:
      • Случаи — Therac-25, Mars Climate Orbiter.
      • Описание — эго может встать на пути объективной оценки систем. Самоуверенность может заставить нас не подвергать сомнению наши допущения. Результатом такого отношения станет то, что мы не будем обращать внимания на имеющиеся ключи, которые указывают на потенциальные дефекты программ.
    • Неполное тестирование:
      • Случаи: Ariane 5, Mars Climate Orbiter, Pentium, авария на AT&T 1990 года.
      • Описание — легко рассуждать, глядя в прошлое, но большая часть этих ошибок могла бы быть обнаружена при «правильном» тестировании. В случае Ariane 5 неполнота требований и недостаток возможностей по имитации функциональной среды привели к тому, что инженеры вынуждены были отказаться от теста, который обнаружил бы ошибку. Неясно, проводилось ли тестирование в случае с Mars Climate Orbiter, поскольку персонал в ходе космического полета все еще занимался устранением ошибок. В случаях ошибки в процессоре Pentium и аварии на AT&T 1990 года проведенные тесты не принимали во внимание особенности алгоритма, поэтому некоторая часть кода не была протестирована. В случае с ошибкой в Pentium тестирование на основе случайной выборки не было достаточным для оценки всех значений в справочной таблице. При аварии на AT&T 1990 года тест не охватывал сценарий восстановления коммутатора.
    Задача

    Вы тестировали набор Web-страниц на Web-сайте вашей компании. Вы нажали на ссылку на Web-страницу А, и все прошло великолепно. Вы продолжили тестирование других Web-страниц на сайте и случайно вернулись на Web-страницу А опять. Но в этот раз ее содержимое оказалось устаревшим. Вы недоуменно посмотрели на страницу и перезагрузили ее. Теперь она снова выглядела нормально. Не доверяя тому, что вы видите, вы опять перезагрузили страницу, и страница снова оказалась правильной. Полагая, что три — это число магическое, вы подумали про себя, что если страница и теперь окажется правильной, значит, то, что вы видели, — это просто случайность. Вы перезагрузили страницу еще раз, и оказалось, что ее содержимое снова является устаревшим. Вы боднули головой монитор. После 10 минут, проведенных в перезагрузке этой страницы снова и снова, вы определили, что она загружается правильно 34 раза и неправильно 12 раз. Что может быть причиной ошибки?

    Вот некоторые подсказки, которые помогут вам поразмышлять о причине ошибки. Архитектурно есть пять Web-серверов, обрабатывающих запросы браузера. Каждый Web-сервер может связываться с одним из четырех серверов приложений. Сервер приложений извлекает данные из базы данных и реализует бизнес-правила. Для ускорения работы каждый сервер хранит данные в локальном кэше.


  • 1 Национальный комитет no аэронавтике и исследованию космического пространства, НАСА (США). — Примеч. пер.

    2 Gleick, James. Genius, The Life and Science of Richard Feynman. Vintage Books, New-York, New York, 1992.

    3 Опустив уплотнительное кольцо в ледяную воду, Р. Фейнман продемонстрировал широкоизвестный факт, что при низких температурах жесткость резины увеличивается, что привело к ослаблению уплотнительных свойств прокладки, утечке топлива и в конце концов к взрыву. — Примеч. науч. ред.

    4 Feynman, Richard P. The Pleasure of Finding Things Out. Perseus Books, Cambridge, Massachusetts, 1999.

    5 Kajihara, J., Amamiya, G., and Saya, T. «Learning from Bugs», IEEE Software, p. 46-54, September 1993.

    6 Leveson, Nancy, and Turner, Clark S. «An Investigation of the Therac-25 Accidents», IEEE Computer, Vol. 26, No. 7, p. 18-41, July 1993.

    7 Там же.

    8 Там же.

    9 Там же.

    10 Там же.

    11 Там же.

    12 Там же.

    13 Там же.

    14 Там же.

    15 Nathan, Adam. «NATO Creates Computer Virus That Reveals Its Secrets», The Sunday Times, June 18, 2000. www.thetimes.co.uk/news/pages/sti/2000/06/18/stinwenws01024.html.

    16 Nicely, Thomas R. Pentium FPU Bug, Memo available on acavax.lynchburg.edu.

    17 Nicely, Thomas R. Letter to Intel, October 30, 1994.

    18 Wolfe, Alexander. EE Times, Issue 822, p. 1, November 7, 1994.

    19 Markoff, John. «Circuit Flaw Causes Pentium Chip to Miscalculate, Intel Admits,» New York Times. November 24, 1994.

    20 Pratt, V. R. «A natural scenario with high FDIV bug probability (was: In Intel’s Defense…)», comp.arch newsgroup, December 3, 1994, 15:20:17 UTC.

    21 IBM, Pentium Study, IBM Memo, December 12, 1994.

    22 Sharangpani, H. P., and Barton, M. L. «Statistical Analysis of Floating Point Flaw in the Pentium Processor (1994)», Intel White Paper, November 30, 1994.

    23 По первым буквам имен авторов Sweeney, Robertson и Tocher, которые независимо друг от друга опубликовали его в 1994 году. — Примеч. науч. ред.

    24 Bryant, R. «Bit-level analysis of an SRT circuit», CMU technical report, CMU-CS-95-140, 1995.

    Sharangpani, H. P., and Barton, M. L. «Statistical Analysis of Floating Point Flaw in the Pentium Processor (1994)», Intel White Paper, November 30, 1994.

    25 Edelman, Alan. «The Mathematics of the Pentium Division Bug», 1995. Available from www-math.mit.edu/-edelman/.
    Also appears in SIAM Review, March 1997.

    26 Pratt, V. R. «A natural scenario with high FDIV bug probability (was: In Intel’s Defense…)», comp.arch newsgroup, December 3, 1994, 15:20:17 UTC.

    27 Edelman, Alan. «The Mathematics of the Pentium Division Bug», 1995. Available from www-math.mit.edu/-edelman/.
    Also appears in SIAM Review, March 1997.

    28 Lions, J. L., et al. «ARIANE 5 Flight 501 Failure», Report by the Inquiry Board. Paris, July 19, 1996. Available at www.csrin.esa.int/htdocs/tidc/Press/Press96/ariane5rep.html.

    29 Lions, J. L., et al. «ARIANE 5 Flight 501 Failure», Report by the Inquiry Board. Paris, July 19, 1996. Available at www.csrin.esa.int/htdocs/tidc/Press/Press96/ariane5rep.html.

    30 Wharton, J. «Super Bowl XXXIV Web-Filtered: Adult Porn?», Risk Digest, Vol 20, No. 77. January 26, 2000. catless.ncl.ac.uk/Risks.

    31 Программа замещает звездочками части слов, которые интерпретирует как отдельные слова с оскорбительным смыслом — Прим. пер.

    32 McWilliams, P. «BBC Censorship», rec.humor.funny, December 3, 1999.
    www.netfunny.com/rhf/jokes/99/Dec/censorship.html.

    33 Город, где располагается штаб-квартира корпорации Майкрософт — Прим. пер.

    34 Cattarin, G. «Junk-Mail Filters», Risks Digest, Vol. 20, No. 89. catless.ncl.ac.uk/Risks.

    35 Media Relations Office, Jet Propulsion Laboratory. «NASA’s Mars Climate Orbiter Believed to Be Lost». NASA Press Release. September 23, 1999.

    36 Mars Climate Orbiter Mishap Investigation Board, Phase 1 Report, November 10, 1999.

    37 Isbell, Douglas; Hardin, Mary; and Underwood, Joan. «Mars Climate Orbiter Team Finds Likely Cause of Loss», NASA Press Release 99-113, September 30, 1999.

    38 Mars Climate Orbiter Mishap Investigation Board, Phase 1 Report, November 10, 1999.

    39 Cook, Michael. «A Self-Referential Risky Accident», Risks Digest, Vol. 20, No. 95.

    40 Термин, означающий добавление к части кода специальных символов комментария, чтобы компилятор рассматривал эту часть не как код программы, а как комментарий программиста. — Прим. пер.

    41 Neumann, Peter. «Risks to the Public in Computers and Related Systems», ACM SIGSOFT Software Engineering Notes, Vol. 15, No. 2, p. 11ff, April 1990.

    42 Neumann, Peter. «Risks to the Public in Computers and Related Systems», ACM SIGSOFT Software Engineering Notes, Vol. 15, No. 2, p. 11ff, April 1990.

    43 Neumann, Peter G. Computer Related Risks. Addison-Wesley, New York, New York, 1995.

    44 Trunk — устройство или канал, соединяющий две точки, каждая из которых является коммутационным центром или точкой распределения; обычно транк работает с несколькими каналами одновременно. — Примеч. пер.

    45 «AT&T Announces Cause of Frame-Relay Network Outage», AT&T Press Release, April 22, 1998. McCartney, Laton. «One Year Later: A Behind-the-Scenes Look at the Causes of and Fallout from AT&T’s Devastating Frame-Relay Outage», Network World, March 22, 1999.

    46 Bernstein, L., and Yuhas, C. M. «Chinks in the Armor: Will a Hybrid IP/ATM Architecture Protect the Network from Node Failures?» America’s Network Magazine, July 1, 1998.

    47 Bernstein, L., and Yuhas, C. M. «Chinks in the Armor: Will a Hybrid IP/ATM Architecture Protect the Network from Node Failures?» America’s Network Magazine, July 1, 1998

    48 «Aleph One», Smashing the Stack for Fun and Profit, Phrack, 7(49), November 1996.

    49 Термин «оборонительное программирование» представляет подход, при котором программист при написании кода сразу же принимает все меры, направленные на обнаружение и исправление всех ошибок, которые могут возникнуть при выполнении этого кода. — Примеч. науч. ред.

    50 Cowan, C., et al. «Buffer Overflows: Attacks and Defenses for the Vulnerability of the Decade», Proceedings of DARPA Information Survivability Conference and Expo. Available from www.wirex.com/~Crispin.

    VPS/VDS серверы. 30 локаций на выбор

    Серверы VPS/VDS с большим диском

    Хорошие условия для реселлеров

    4VPS.SU — VPS в 17-ти странах

    2Gbit/s безлимит

    Современное железо!


    Бесплатный конструктор сайтов и Landing Page

    Хостинг с DDoS защитой от 2.5$ + Бесплатный SSL и Домен

    SSD VPS в Нидерландах под различные задачи от 2.6$

    ATLEX

    Выделенные серверы: в Европе / в России.

    Виртуальные серверы: в Европе / в России.

    Партнерская программа

    Новости мира IT:

    • 09.02 — Релиз Chrome 110
    • 09.02 — Роскосмос выполнил 100 успешных космических запусков подряд — это новый рекорд
    • 09.02 — Amazon получила разрешение на запуск интернет-спутников Project Kuiper
    • 09.02 — В браузере Opera тоже появится ИИ-бот ChatGPT
    • 09.02 — ИИ-ботов становится всё больше: Alibaba создала и тестирует свой аналог ChatGPT
    • 09.02 — Смарт-часы с поддержкой 5G появятся в следующем году — Qualcomm представила компактный модем Snapdragon X35
    • 09.02 — Продажа «Билайна» команде местных топ-менеджеров получила окончательное одобрение
    • 07.02 — Apple исполнила предписание ФАС и не будет ограничивать выпуск приложений в App Store, если они соответствуют правилам
    • 07.02 — Google разрабатывает Chrome для iOS на движке Blink — он нарушает правила Apple App Store
    • 07.02 — Apple проведёт AI summit для сотрудников в очном формате впервые за три года
    • 07.02 — Microsoft регистрирует через Роспатент товарный знак Dragon, связанный с ПО для распознавания речи
    • 07.02 — Google представила ИИ-бота Bard — ответ на ChatGPT, до которого допустит только «правильных тестировщиков»
    • 07.02 — Sumitomo Electric намерена обеспечить системы хранения электроэнергии аккумуляторами с ресурсом до 30 лет
    • 02.02 — Власти РФ согласовали сделку по продаже «Билайна» российскому топ-менеджменту — акции компании выросли
    • 02.02 — Сергей Брин снова начал работать программистом в Google
    • 02.02 — МТС начнёт выпускать в Твери автомобильные мультимедийные системы с навигацией
    • 02.02 — В России возник дефицит чипов для документов — проблема затронула загранпаспорта нового образца
    • 01.02 — Microsoft прекратила прямые продажи Windows 10
    • 01.02 — «Яндекс» интегрирует в поиск и другие сервисы свой аналог ChatGPT до конца года
    • 01.02 — Солнце и ветер дали Европе больше электроэнергии, чем любой другой источник в 2022 году

    Архив новостей

    • 4VPS.SU: виртуальные серверы в 17 странах мира на любой бюджет

    IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

    Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,

    тел. +7 495 7861149
    Пресс-релизы — pr@citforum.ru

    Обратная связь
    Информация для авторов

    Rambler's Top100 TopList liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня This Web server launched on February 24, 1997
    Copyright © 1997-2000 CIT, © 2001-2019 CIT Forum

    Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее…

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

    Катастрофа Ariane 5
    Инциденты с Therac-25
    Мифы о безопасности ПО
    Эпитафия
    Эпилог
    Литература

    «Если бы строители строили здания так же, как программисты пишут программы, первый залетевший дятел разрушил бы цивилизацию»

    «Если бы строители строили здания так же, как программисты пишут программы, первый залетевший дятел разрушил бы цивилизацию», — второй закон Вейлера.

    Не секрет, что ошибки в программном обеспечении «ответственных» систем могут вызвать чрезвычайные последствия, тем не менее, в обществе, особенно на уровне массового потребителя ИТ, продолжает витать иллюзия непогрешимости компьютера и работающего на нем ПО. В статье подробно разбираются две вошедших в историю компьютерной индустрии катастрофы и обсуждаются некоторые мифы, связанные с такими понятиями, как безопасность и риски в контексте разработки и эксплуатации программно-аппаратных систем.

    Слово «безопасность» не сходит со страниц компьютерной прессы. Однако, употребляется оно обычно в контексте поддержания целостности данных и — особенно — обеспечения их конфиденциальности. Что ж, тема интересная: Internet, банки, спецслужбы, хакеры … — все, к чему приложимо вошедшее в повседневный обиход слово «seсurity». Есть, однако, у «безопасности» и другое измерение, чаще обозначаемое не столь популярным термином «safety», про которое говорят меньше, но важность его — применительно к компьютерным системам — поистине нельзя переоценить.

    В мире постоянно происходят катастрофы, большие, малые аварии и все чаще их причиной становится ненадлежащее функционирование компьютерных систем и, в частности, их программного обеспечения. Оборона, авиация и космос, медицина, технологические процессы на современных ядерных, химических и других производствах — вот неполный перечень тех предметных областей, где низкое качество ПО и даже единичные дефекты в нем находят воплощение в терминах потерянных человеческих жизней и разрушенных материальных ценностей.

    Над такого рода «ответственными» (mission-critical) системами работает целая отрасль, в которой крутятся очень большие (по-преимуществу, бюджетные) деньги и где — как справедливо принято считать — сосредоточено значительное количество высококвалифицированных программистов и проектировщиков, надлежащим образом поставлен менеджмент, отлажены процессы разработки и контроля. И тем не менее, «кое-где… порой…» ПО дает сбой, и резонанс тогда бывет громкий. Разберем две знаменитых истории, в одной из которых программистские ошибки привели к беспрецедентным материальным потерям, в другой — к смерти нескольких человек, и попытаемся за этими частными случаями увидеть некоторые общие проблемы, стоящие сегодня перед всей программной индустрией.

    Катастрофа Ariane 5

    4 июня 1996 года был произведен первый запуск ракеты-носителя Ariane 5 — детища и гордости Европейского Сообщества. Уже через неполные 40 сек. все закончилось взрывом. Автоподрыв 50-метровой ракеты произошел в районе ее запуска с космодрома во Французской Гвиане. За предшествующие годы ракеты серии Ariane семь раз терпели аварии, но эта побила все рекорды по вызванным ею убыткам. Только находившееся на борту научное оборудование потянуло на пол-миллиарда долларов, не говоря о прочих разноообразных издержках; а астрономические цифры «упущенной выгоды» от несостоявшихся коммерческих запусков и потеря репутации надежного перевозчика в очень конкурентном секторе мировой экономики («стоимость рынка» к 2000 г. должна превысить 60 млрд. долл.) с трудом поддаются оценке. Небезынтересно отметить, что предыдущая модель — ракета Ariane 4 — успешно запускалась более 100 раз.

    Буквально на следующий день Генеральный директор Европейского Космического Агенства (ESA) и Председатель Правления Французского Национального Центра по изучению Космоса (CNES) издали распоряжение об образовании независимой Комиссии по Расследованию обстоятельств и причин этого чрезвычайного происшествия, в которую вошли известные специалисты и ученые изо всех заинтересованных европейских стран. Возглавил Комиссию представитель Французской Академии Наук профессор Жак-Луи Лион (Jacques-Louis Lions). Кроме того, был сформирован специальный Технический Комитет из представителей заказчиков и подрядчиков, ответственных за производство и эксплуатацию ракеты, в чью обязанность было вменено незамедлительно предоставлять Комиссии всю необходимую информацию.

    13 июня 1996 г. Комиссия приступила к работе, а уже 19 июля был обнародован ее исчерпывающий доклад, который сразу же стал доступен в Сети [1]. Что же касается информации, которую — при участии нескольких институтов — осмысляла Комиссия, то она состояла из телеметрии, траекторных данных, а также оптических наблюдений за ходом полета. Были собраны (что само по себе было непросто, так как взрыв произошел на высоте приблизительно 4 км, и осколки были рассеяны на площади около 12 кв. км. в саванне и болотах) и изучены части ракеты и оборудования. Кроме того, были заслушаны показания многочисленных специалистов и изучены горы производственной и эксплуатационной документации.

    Технические подробности аварии

    Положение и ориентация ракеты-носителя в пространстве измеряются Навигационной Системой (Inertial Reference Systems — IRS), составной частью которой является встроенный компьютер, вычисляющий углы и скорости на основе информации от бортовой Инерциальной Платформы, оборудованной лазерными гироскопами и акселерометрами. Данные от IRS передаются по специальной шине на Бортовой Компьютер (On-Board Computer — OBC), который обеспечивает необходимую для реализации программы полета информацию и непосредственно — через гидравлические и сервоприводы — управляет твердотопливными ускорителями и криогенным двигателем типа Вулкан (Vulkain).

    Как обычно, для обеспечения надежности Системы Управления Полетом используется дублирование оборудования. Поэтому две системы IRS (одна — активная, другая — ее горячий резерв) с идентичным аппаратным и программным обеспечением функционируют параллельно. Как только бортовой компьютер OBC обнаруживает, что «активная» IRS вышла из штатного режима, он сразу же переключается на другую. Впрочем, и бортовых компьютеров тоже два.

    Теперь, следуя Докладу Комиссии [1], проследим все значимые фазы развития процесса, оказавшегося в конце концов аварийным. Момент старта обозначим H0 — это и будет точка отсчета для всех событий, хотя отслеживать их мы будем в обратном — начиная с момента саморазрушения системы — порядке. Для полноты картины упомянем, что предшествующие старту операции происходили в нормальном режиме вплоть до момента H0-7 минут, когда было зафиксировано нарушение «критерия видимости». Поэтому старт был перенесен на час; в H0 = 9 час. 33 мин. 59 сек. местного времени «окно запуска» было вновь «поймано» и был, наконец, осуществлен сам запуск, который и происходил штатно вплоть до момента H0+37 сек. В последующие секунды произошло резкое отклонение ракеты от заданной траектории, что и закончилось взрывом. Итак:

    • в момент H0+39 сек. из-за высокой аэродинамической нагрузки вследствие превышения «углом атаки» критической величины на 20 градусов произошло отделение стартовых ускорителей ракеты от основной ее ступени, что и послужило основанием для включения Системы Автоподрыва ракеты;
    • изменение угла атаки произошло по причине нештатного вращения сопел твердотопливных ускорителей;
    • такое отклонение сопел ускорителей от правильной ориентации вызвала в момент H0 + 37 сек. команда, выданная Бортовым Компьютером на основе информации от активной Навигационной Системы (IRS 2). Часть этой информации была в принципе некорректной: то, что интерпретировалось как полетные данные, на самом деле являлось диагностической информацией встроенного компьютера системы IRS 2;
    • встроенный компьютер IRS 2 передал некорректные данные, потому что диагностировал нештатную ситуацию, «поймав» исключение (exception), выброшенное одним из модулей программного обеспечения;
    • при этом Бортовой Компьютер не мог переключиться на резервную систему IRS 1, так как она уже прекратила функционировать в течение предшествующего цикла (занявшего 72 мсек.) — по той же причине, что и IRS 2;
    • исключение, «выброшенное» одной из программ IRS, явилось следствием выполнения преобразования данных из 64-разрядного формата с плавающей точкой в 16-разрядное целое со знаком, что привело к «Operand Error»;
    • ошибка произошла в компоненте ПО, предназначенном исключительно для выполнения «регулировки» Инерциальной Платформы. Причем — что звучит парадоксально, если не абсурдно — этот программный модуль выдает значимые результаты только до момента H0 + 7 сек. отрыва ракеты со стартовой площадки. После того, как ракета взлетела, никакого влияния на полет функционирование данного модуля оказать не могло;
    • однако, «функция регулировки» действительно должна была (в соответствии с установленными для нее требованиями) действовать еще 50 сек. после инициации «полетного режима» на шине Навигационной Системы (момент H0-3 сек.), что она с усердием дурака, которого заставили богу молиться, и делала;
    • ошибка «Operand Error» произошла из-за неожиданно большой величины BH (Horizontal Bias — горизонтальный наклон), посчитанной внутренней функцией на основании величины «горизонтальной скорости», измеренной находящимися на Платформе датчиками. Величина BH служила индикатором точности позиционирования Платформы;
    • величина BH оказалась много больше, чем ожидалось потому, что траектория полета Ariane 5 на ранней стадии существенно отличалась от траектории полета Ariane 4 (где этот программный модуль использовался ранее), что и привело к значительно более высокой «горизонтальной скорости».

    Финальным же действием, имевшим фатальные последствия, стало прекращение работы процессора; соответственно, вся Навигационная Система перестала функционировать. Возобновить же ее действия оказалось технически невозможно.

    Осталось добавить, что всю эту цепь событий удалось полностью воспроизвести с помощью компьютерного моделирования, что — вкупе с материалами других исследований и экспериментов — позволило заключить; причины и обстоятельства катастрофы полностью выявлены.

    Причины и истоки аварии

    Прежде всего проследим, откуда взялось первоначальное требование на продолжение выполнения операции регулировки после взлета ракеты. Оказывается, оно было заложено более чем за 10 лет до рокового события, когда проектировались еще ранние модели серии Ariane. При некотором (весьма маловероятном!) развитии событий взлет мог быть отменен буквально за несколько секунд до старта, например в промежутке H0-9 сек., когда на IRS запускался «полетный режим», и H0-5 сек., когда выдавалась команда на выполнение некоторых операций с ракетным оборудованием. В случае неожиданной отмены взлета необходимо было быстро вернуться в режим «обратного отсчета» (countdown) — и при этом не повторять сначала все установочные операции, в том числе приведение к исходному положения Инерциальной Платформы (операция, требующая 45 мин. — время, за которое можно потерять «окно запуска»).

    Было обосновано, что в случае события отмены старта период в 50 сек. после H0-9 будет достаточным для того, чтобы наземное оборудование смогло восстановить полный контроль за Инерциальной Платформой без потери информации — за это время Платформа прекратит начавшееся было перемещение, а соответствующий программный модуль всю информацию о ее состоянии зафиксирует, что поможет оперативно возвратить ее в исходное положение (напомним, что все это в случае, когда ракета продолжает находиться на месте старта). И действительно, однажды, в 1989 году, при старте под номером 33 ракеты Ariane 4, эта особенность была с успехом задействована.

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

    В конце концов, было бы странно, если бы тривиальная ошибка переполнения (даже если она и возникла) была бы столь фатальной, что с ней невозможно бороться. Почему же программный код (написанный на таком оснащенном всеми необходимыми для обеспечения надежности средствами языке, как Ада) оказался незащищеным до такой степени, что наступили столь катастрофические последствия?

    Расследование показало, что в данном программном модуле присутствовало целых семь переменных, вовлеченных в операции преобразования типов. Оказалось, что разработчики проводили анализ всех операций, способных потенциально генерировать исключение, на уязвимость. И это было их вполне сознательным решением добавить надлежащую защиту к четырем переменным, а три — включая BH — оставить незащищенными. Основанием для такого решения была уверенность в том, что для этих трех переменных возникновение ситуации переполнения невозможно в принципе. Уверенность эта была подкреплена расчетами, показывающими, что ожидаемый диапазон физических полетных параметров, на основании которых определяются величины упомянутых переменных, таков, что к нежелательной ситуации привести не может. И это было верно — но для траектории, рассчитанной для модели Ariane 4. А ракета нового поколения Ariane 5 стартовала по совсем другой траектории, для которой никаких оценок не выполнялось. Между тем она (вкупе с высоким начальным ускорением) была такова, что «горизонтальная скорость» превзошла расчетную (для Ariane 4) более чем в пять раз.

    Но почему же не была (пусть в порядке перестраховки) обеспечена защита для всех семи, включая BH, переменных? Оказывается, для компьютера IRS была продекларирована максимальная величина рабочей нагрузки в 80%, и поэтому разработчики должны были искать пути снижения излишних вычислительных издержек. Вот они и ослабили защиту там, где теоретически нежелательной ситуации возникнуть не могло. Когда же она возникла, то вступил в действие такой механизм обработки исключительной ситуации, который оказался совершенно неадекватным.

    Этот механизм предусматривал следующие три основных действия. Прежде всего, информация о возникновении нештатной ситуации должна быть передана по шине на бортовой компьютер OBC; параллельно она — вместе со всем контекстом — записывалась в перепрограммируемую память EEPROM (которую во время расследования удалось восстановить и прочесть ее содержимое), и наконец, работа процессора IRS должна была аварийно завершиться. Последнее действие и оказалось фатальным — именно оно, случившееся в ситуации, которая на самом деле была нормальной (несмотря на сгенерированное из-за незащищенного переполнения программное исключение), и привело к катастрофе.

    Осмысление

    Произошедшая с Ariane 5 катастрофа имела исключительно большой резонанс — и по причине беспрецедентных материальных потерь, и вследствие очень оперативного расследования, характеризовавшегося к тому же открытостью результатов (впервые такая практика публичности была опробована при расследовании причин аварии космического корабля Challenger в 1986 году). Сразу стало очевидным, что данному событию суждено войти в историю не только космонавтики, но и программной инженерии. Поэтому неудивительно, что авария послужила поводом для оживленной дискуссии, в которой приняли участие многие известные специалисты.

    Ж.-М. Жезекель (J.-M. Jezequel) и Бертран Мейер (B.Meyer) [2] пришли к совершенно однозначному выводу: допущенная (и так и не выявленная) программная ошибка носит, по их мнению, чисто технический характер и коренится в некорректной практике повторного использования ПО. Более точная формулировка: роковую роль сыграло отсутствие точной спецификации повторно-используемого модуля. Расследование показало, что обнаружить требование, устанавливающее максимальную величину BH (вмещающуюся в 16 битов), можно было с большим трудом: оно затерялось в приложениях к основному спецификационному документу. Мало того, в самом коде на этот счет не было никаких комментариев, не говоря уже о ссылке на документ с обоснованием этого требования.

    В качестве панацеи в такого рода ситуациях авторы предложили задействовать принцип «Контрактного Проектирования» (что и неудивительно, ибо его разработчиком как раз и является Мейер [3]). Именно «контракт» в духе языка Eiffel, явным образом (с помощью пред- и пост-условий) устанавливающий для любого программного компонента ограничения на входные и выходные параметры, и мог бы предотратить катастрофическое развитие событий. Был приведен и набросок такого контракта:

    
    

    convert (horizontal_bias:INTEGER): INTEGER is require horizontal_bias <= Maximum_bias do … ensure … end

    Соответственно, ошибка могла быть выявлена уже на этапе тестирования и отладки (когда проверка логических утверждений включается по специальной опции компилятора); если же пред- и пост-условия проверялись бы и во время полета, то сгенерированное исключение могло быть надлежащим образом обработано (правда, авторы оговариваются, что использование такого режима могло бы нарушить ограничения, связанные с вычислительной нагрузкой). Однако, самым важным достоинством использования контрактных механизмов является, по мнению авторов, явное присутствие легко понимаемых и при необходимости верифицируемых ограничений как в документации, так и в коде. При работе над сложными проектами типа Ariane именно контракты могли бы выступать в качестве опорных ориентиров для групп качества «QA Team», чья задача — выполнять систематический мониторинг ПО на предмет соответствия требованиям. Авторы с сожалением заключают, что контрактные механизмы никак не получат должного распространения в современной практике. Более того, положение только усугубляется: например, в Java даже исчезла присутствовавшая в языке Cи скромная по возможностям инструкция «assert». В составной части CORBA — языке IDL (Interface Definition Language), предназначенном обеспечить полномасштабное повторное использование компонентов в распределенной среде, отсутствует какой-либо механизм спецификации семантики. То же относится и к ActiveX. Авторы заключают: без полной и точной спецификации, основанной на пред- и пост-условиях и инвариантах, «повторное использование программных компонентов — совершенное безрассудство».

    Эта точка зрения вызвала многочисленные отклики. Хотя полезность использования контрактных механизмов никто не оспаривал, все же взгляд авторов многим показался упрощенным. Наиболее обстоятельный критический разбор их статьи выполнил сотрудник Locheed Martin Tactical AirCraft Systems, известный специалист в области разработки ответственных систем Кен Гарлингтон (Ken Garlington) [4]. Он начал с того, что указал на ошибку в приведенном наброске контракта, где предполагается, что BH преобразуется не из вещественного (как то было в реальности) числа, а из целого. Показательно, пишет Гарлингтон, что он оказался первым, кто обратил внимание на столь очевидный прокол, а ведь статью читали и публично обсуждали многие квалифицированные специалисты. С тем же успехом (а точнее неуспехом) могла пройти мимо этого дефекта и «QA-team». Так что даже точная спецификация сама по себе не панацея. Гарлингтон также подробно разобрал нетривиальные проблемы, возникающие при написании не «наброска», а действительно полной спецификации контракта для данной конкретной ситуации.

    Вывод Гарлингтона вполне отвечает здравому смыслу: проблема носит комплексный характер и обусловлена прежде всего объективной сложностью систем типа Ariane. Соответственно, одним лекарством болезнь, приводящая к появлению ошибок в ПО, вылечена быть не может. Хотя то, что процесс мониторинга спецификаций, кода и документов с обоснованием проектных решений при разработке ПО для Ariane 5, оказался неадекватен, отметила и Комиссия по расследованию аварии. В частности, подчеркнуто, что к процессу контроля не привлекались специалисты из организаций, независимых как от заказчика, так и от подрядчика системы, что нарушило принцип разделения исполнительных и контрольных функций.

    Большие претензии были предъявлены не только к процессу тестирования как таковому, но и к самой его стратегии. На этапе тестирования и отладки системы было технически возможно в рамках интегрального моделирования процесса полета исследовать все аспекты работы IRS, что позволило бы почти гарантированно выявить ошибку, приведшую к аварии. Однако, вместо этого при моделировании работы всего комплекса IRS рассматривалась как черный ящик, заведомо выдающий то, что ожидается. Почему? А зачем тестировать то, что успешно работало в течение многих лет?!

    Было обращено внимание и на невыявленную при анализе требований к проекту взаимную противоречивость между необходимостью обеспечения надежности и декларацией о величине максимально допустимой нагрузки на компьютер, что и явилось предпосылкой принятия программистами потенциально опасного компромиссного решения о защите от переполнения не всех семи, а только четырех переменных. Впрочем, как справедливо замечает Мейер, всякий инженерный процесс предполагает принятие компромиссных решений в условиях множества разноречивых требований; вопрос в том, насколько полна информация, на основании которой такие решения принимаются.

    Особый разговор — о механизме обработки исключительных ситуаций, который, как уже говорилось, жил своей особой жизнью — в отрыве от общего контекста всей ситуации с полетом, и в итоге уподобился тому врачу, что без всякого осмотра пристрелил пришедшего к нему с непонятными симптомами больного, дабы тот не мучился. Реализация именно такого механизма явилась следствием распространенной при разработке «ответственных» систем проектной культуры особо — и радикально — реагировать на возникновение случайных аппаратных сбоев. Принцип действий здесь «простой, как мычание», исходящий из критериев безусловного обеспечения максимальной надежности: отключать допустившее сбой оборудование и тут же задействовать резервный блок: вероятность того, что этот блок также выдаст случайный сбой, да еще в той же ситуации, для надлежаще спроектированных и отлаженных аппаратных систем чрезвычайна мала.

    В данном же случае, возникла систематическая программная ошибка; «систематическая» — в том смысле, что при повторении тех же входных условий, она обязательно возникнет вновь, ибо — тавтология здесь уместна — запрограммирована. Вот почему подключение резервной Навигационной Системы ничего не дало: ведь ПО на нем исполнялось то же самое, соответственно и обе IRS, и дублирующие друг друга Бортовые Компьютеры с неотвратимостью натыкались на ту же ситуацию и с покорностью обреченных на заклание овец шли к катастрофе. Очевидно, что необходимо по крайней мере отнять у «врача» пистолет: прекращать функционирование аппаратуры при возникновении программного «исключения» целесообразно лишь после комплексного анализа ситуации, но никак не автоматически.

    В контексте данной статьи интересно мнение главного редактора журнала «Automated Software Engineering» Башара Нузейбеха (Bashar Nuseibeh) [5], который, дав обзор разных точек зрения на причины аварии и придя к выводу, что «все правы», связал все-таки катастрофу Ariane 5 с более общими проблемами разработки программных систем. Он отметил, в частности, что современные тенденции в программной инженерии, связанные с разделением интересов вовлеченных в разработку независимо работающих персонажей (что связано с широким внедрением таких подходов, как объектно-ориентированные и компонентные технологии) не получают надлежащего балансирующего противовеса в виде менеджмента, способного координировать всю работу на должном уровне. Эта тема заслуживает дальнейшего обсуждения, но сначала обратимся к еще одной печально знаменитой истории.

    Инциденты с Therac-25

    Вспомним более давнюю историю, почти во всем отличную от ситуации с Ariane 5, а сходную только в том, что она также была подробно задокументирована [6] и получила в свое время большой резонанс как повлекшая наиболее тяжкие последствия за всю не столь долгую историю использования медицинских комплексов, управляемых компьютерами. Правда в этом случае полномасштабного официального расследования проведено не было; источниками информации послужили, в основном, протоколы встреч пользователей системы с производителем и материалы многочисленных судебных разбирательств.

    Технические подробности инцидентов

    В 1985-87 гг. 6 человек получили смертельную дозу облучения во время сеансов радиационной терапии с применением медицинского ускорителя Therac-25 (количество пациентов, также подвергшихся переоблучению, но выживших, точно не известно). Производителем установки являлось одно из подразделений Канадского Агентства Атомной Энергии (Atomic Energy of Canada Limited — AECL). Модель Therac-25, законченная в виде прототипа в 1976 г. и поступившая в промышленную эксплуатацию в 1982 г. (пять установок в США и шесть — в Канаде) была развитием ранних моделей Therac-6 и Therac-20. При этом некоторые программные модули, разработанные для ранних моделей, использовались повторно (в том числе — поставленные партнером, французской фирмой CGR, сотрудничество AECL с которой прекратилось к моменту начала работ над Therac-25).

    Следующий инцидент, случившийся в июле того же года в Онкологическом Центре Онтарио как раз был задокументирован хорошо, но производитель не смог воспроизвести ситуацию, и ее отнесли на счет случайного сбоя аппаратуры; в ПО сомнений по-прежнему просто не было. И трагические инциденты продолжились.

    Очередной из них произошел в Онкологическом Центре Восточного Техаса в марте 1986 года. В данном случае процессом управляла опытный оператор, проведшая уже более 500 подобных сеансов. Она быстро ввела предписанные параметры, после чего заметила, что вместо режима облучения электронными лучами заказала лучи рентгеновские (которыми пользовали большинство пациентов). Коррекция требовала исправления всего одной буквы; нажав кнопку, она вошла в режим редактирования, скорректировала в нужном месте «x» на «e», затем несколькими нажатиями клавиши «Return» (благо, все остальные параметры были введены правильно) достигла нижней (командной) строки экрана, убедилась, что против каждого введенного параметра горит «VERIFIED», а статус системы — ожидаемый («BEAM READY»), и выдала команду начать процесс облучения. Однако, неожиданно система встала, на консоли высветилось сообщение «MALFUNCTION 54», а статус системы изменился на «TREATMENT PAUSE», что свидетельствовало о проблеме невысокой степени серьезности. Висевшая тут же бумага с кодами ошибок «исчерпывающе» поясняла, что «MALFUNCTION 54» означает «dose input 2». Забегая вперед, укажем, что много позже, во внутренней документации производителя было обнаружено, что это сообщение выдавалось в случае «ненадлежащей дозы облучения» — причем, как для слишком большой, так и для слишком малой, что само по себе странно (да и просто недопустимо — ведь ситуации принципиально разные). Озадаченная операторша взглянула на высветившееся количество отпущенной дозы и увидела, что оно — пренебрежимо мало. Поэтому она без долгих раздумий выдала команду на продолжение процесса, после чего вся описанная выше ситуация повторилась.

    Тем временем пациент, который возлежал на столе в изолированном от оператора помещении, испытал некое подобие электрического шока. Он тоже был опытным (для него это был девятый сеанс), поэтому понял, что творится что-то неладное. Однако, дать сразу же знать об этом оператору через специально для того предназначенные видео и аудио средства он не смог: как выяснилось, видео было по непонятным причинам отключено, а аудиоканал — просто неисправен. После повторного шокового удара пациент вскочил и нимало шокировал уже операторшу, начав ломиться в стеклянные двери ее помещения. Поначалу его и лечили от электрошока (он умер через пять месяцев). Позднейшее моделирование ситуации показало, что пациент получил менее чем за 1 сек. на участок позвоночника в 1 кв. см. дозу в диапазоне от 16500 до 25000 рад (в то время, как ему было предписано принять в этом сеансе 180 рад, а всего — 6000 рад за шесть с половиной недель).

    Прибывший из AECL инженер, несмотря на все усилия, оказался не в состоянии воспроизвести ситуацию, хотя заверил, что переоблучение в принципе невозможно. Были успешно прогнаны все тесты, система снова вступила в эксплуатацию, и через три недели инцидент повторился во всех деталях — с тем же трагическим результатом. Только после этого установка была выведена из эксплуатации, и началось углубленное расследование, шедшее, кстати, очень трудно. Опуская множество деталей, приведем его итоги, интересные с программистской точки зрения.

    Особенности ПО как предпосылки для инцидентов

    В комплексе не использовалась какая-либо стандартная операционная система: была разработана специальная мультизадачная ОС реального времени, для компьютера PDP-11/23 с 32Kбайт и написанная на языке ассемблера. Специальный планировщик координировал деятельность всех одновременно исполняющихся процессов. Задачи, запускавшиеся каждые 0,1 сек., разделялись на «критические», исполнявшиеся первыми, и «некритические». К критическим отнесены три приоритетных задачи (рис. 1):

    • «Servo», ответственная за все операции, связанные с эмиссией радиационных пучков и доставкой их к месту назначения;
    • «Housekeeper», выполнявшая верификацию всех параметров и ответственная за блокировку работы в случае возникновения нештатной ситуации, а также за сообщения о таких ситуациях;
    • «Treat», управлявшая самим процессом лечения, который был разделен на 8 операционных фаз. В зависимости от значения переменной Tphase вызывалась одна из восьми подпрограмм, по окончании работы которой Treat — в зависимости от значений нескольких разделяемых с другими критическими и некритическими задачами переменных, вырабатывала план на новый цикл.

    Рис. 1
    Рис. 1. Взаимодействие задач и подпрограмм в ПО для Therac-25

    Одна из вызываемых Treat подпрограмм — Datent (Data entry) через разделяемую «флаговую» переменную Data_entry_complete взаимодействует с «некритической» задачей Keyboard Handler, которая управляет вводом информации с клавиатуры, исполняясь параллельно с Treat. Keyboard Handler распознает момент окончания ввода и сигнализирует об этом, изменяя значение Data_entry_complete. В свою очередь, Datent проверяет значение этой переменной. Если оно не изменилось, то значение Tphase остается равным «1», и на следующем цикле Treat опять запустит Datent; если же значение Data_entry_complete изменилось, то Datent меняет значение Tphase с «1» на «3»; в результате после окончания работы Datent монитор Treat вызовет подпрограмму Set Up Test, выполняющую проверку считающихся уже установленными параметров.

    Необходимо упомянуть еще одну переменную MEOS ( Mode/Energy Offset), разделяемую между Datent, Keyboard Handler и еще одной некритической задачей Hand. Старшие байты MEOS используются подпрограммой Datent для установки одного из двух режимов облучения и величины энергии испускаемого потока, в то время как младшие используются параллельно работающей задачей Hand для установки коллиматора в положение, соответствующее выбранному режиму и энергии.

    Оператор мог после ввода параметров режима и энергии редактировать эти величины по отдельности. Однако, здесь присутствовал тонкий момент — разработчики установили: об окончании процесса ввода (и редактирования!) параметров свидетельствует то, что все параметры заданы и курсор находится в командной строке, на предмет чего каждые 8 сек. (величина выбрана, исходя из некоторых технических соображений, связанных с инерционностью приборов) производится опрос переменной Data_entry_complete. Если в пределах этих 8 сек. курсор покидает командную строку и — после быстрого редактирования параметров — успевает вернуться на нее, то Keyboard Handler этого события просто не заметит, и соответственно, никак переменную Data_entry_ complete не изменит. Иными словами, потенциально существует возможность для следующей последовательности действий:

    • Keyboard Handler отследил местонахождение курсора на командной строке и установил флаг Data_entry_complete;
    • затем оператор изменил данные в MEOS;
    • не заметив этого (если к моменту опроса курсор оказался вновь на командной строке), Keyboard Handler не переустанавливает флаг Data_entry_complete;
    • тогда Datent уже не способна обнаружить изменение MEOS — она свою работу закончивает, установив Tphase=3 (а не Tphase=1, чтобы отработать еще один цикл и учесть изменения);
    • тем временем, параллельно работающая Hand устанавливает коллиматор в положение, соответствующее младшим байтам MEOS (их установила ранее Datent), которые могли находиться в противоречии со старшими байтами этой разделяемой переменной (как раз и подвергшимся редактированию!). Специальных проверок для обнаружения такой несовместимости предусмотрено не было.

    Сноровистая и уже набившая на этой работе руку операторша, в отличие от неторопливых инженеров AECL, скорректировала «режим» и вернула курсор обратно на командную строку очень быстро — уложившись в 8 сек. В итоге, проделанное ею изменение режима воспринято не было — он остался прежним (рентгеновским), а вот задаваемые параметры (включая находящиеся в младших байтах MEOS, критически влияющие на величину и направление потоков частиц) соответствовали электронному (фотонному) режиму. Последний штрих в катастрофическую картину внесли показания дозиметра, дававшего показания в «условных единицах» — то, что высвеченная «малая» величина дозы относилась к другому режиму и потому не подлежала рациональной оценке, операторше не пришло в голову.

    Скорректировать данную ошибку удалось просто — введением еще одной разделяемой переменной, которая изменяла значение, как только курсор покидал командную строку. Настоящая беда, однако, заключалась в том, что ошибка такого рода (классическая ошибка, связанная с неправильной синхронизацией одновременно идущих процессов, использующих разделяемые переменные, и приводящая к «race condition») — была далеко не единственной.

    Программная блокировка и ее последствия

    Рассмотрим еще один инцидент с Therac-25, которому суждено было стать последним. Он произошел в Yakima Valley Memorial Hospital (штат Вашингтон) в январе 1987 г. Пациенту было предписано сначало проделать два рентгеновских снимка с дозой в 4 и 3 рад соответственно, а затем произвести в фотонном режиме облучение в 86 рад. Все это и было выполнено, однако, как потом было установлено, пациент получил переоблучение фотонной дозой до 10000 рад. (Установлено было «потом», а не сразу — оператор, сделав снимки, забыл вынуть рентгеновскую пленку из-под пациента, из-за чего у него на консоли горели все те же 7 рад; однако, и правильная индикация уже выданной дозы была бы здесь как — в буквальном смысле слова — мертвому припарки).

    Что же произошло? Выявленная в итоге расследования проблема выходит далеко за пределы частного случая еще одной программистской ошибки. В данном случае не сработала блокировка, реализованная программно позволившая прибору действовать (испускать поток фотонов) при ошибочной установке параметров. Ситуация возникла в момент, когда введенные параметры уже верифицированы подпрограммой Datent и монитор Treat в соответствии со значением переменной Tphase = 3 вызвал подпрограмму Set Up Test.

    Во время установки и подгонки параметров подпрограмма Set Up Test вызывается несколько сотен раз — пока все параметры не будут установлены и верифицированы, о чем эта подпрограмма судит по нулевому значению разделяемой переменной F$mal. Если же значение ненулевое — цикл повторяется. F$mal, в свою очередь, устанавливается подпрограммой Chkcol (Check Collimator) из критической задачи Housekeeper, проверяющей, все ли с коллиматором нормально; а вызывает Chkcol другая подпрограмма задачи Housekeeper под названием Lmtchk (analog-to-digital limit checking), и вызов этот происходит, только если значение разделяемой переменной Class3 ненулевое. А ненулевым его делает как раз сама Set Up Test, которая (пока F$mal=0) каждый раз выполняет над Class3 операцию инкремента.

    Эта переменная — однобайтовая, следовательно каждый 256-й проход заставляет ее сбрасываться в ноль. А ведь этот ноль — свидетельство, что все параметры, наконец, установлены. Если повезет, что именно в этот момент оператор нажмет клавишу «set» для запуска установки коллиматора в надлежащую позицию (а он это может сделать в любой момент, так как уверен, что система позволит коллиматору начать позиционироваться, только если все параметры заданы и верифицированы), то основываясь на случайно возникшем нулевом значении Class3, подпрограмма Lmtchk уже не станет вызывать Chkcol, а значит установить ненулевое значение F$mal будет некому. Иными словами, в ситуации, когда параметры не установлены должным образом (в данном конкретном случае «челюсти» коллиматора были еще раскрыты слишком широко), программная блокировка не сработала: Set Test Up установила Tphase = 2, что позволило монитору Treat прекратить цикл вызова Set Up Test, а инициализировать подпрограмму Set Up Done, по существу запускающую процесс излучения, который и потек бурным потоком, а не узеньким ручейком, как предполагалось.

    Коррекция этой ошибки также выполняется просто — вместо выполнения инкремента переменной Class3 следует просто присваивать фиксированное ненулевое значение. Вот от каких, казалось бы, мелких и чисто технических ляпсусов программиста может зависеть жизнь человека!

    Некоторые итоги

    История с Therac-25 показательна, прежде всего, своей комплексностью: если в случае с Ariane 5 авария случилась один раз и из-за единственной ошибки, то катастрофические последствия с Therac-25 проявлялись неоднократно в течение длительного времени, и были следствием целого спектра причин, среди которых не только вполне конкретные программистские «баги», но и дефекты в самой постановке выполнявшегося многие годы проекта.

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

    Что же до системной «глобальной особенности», то к ней можно отнести принципиальную переусложненность построения мультизадачной управляющей системы. С чисто программистской точки зрения можно отметить, что для реализации тонкой синхронизации параллельных процессов был выбран механизм разделения переменных, требующий очень внимательной проработки (это именно та область, где необходимо выполнять формальное доказательство правильности алгоритма, благо соответствующие методы разработаны и могут считаться рутинными — для тех, кто ими владеет); получилось же так, что потенциально опасные в плане возникновения «race conditions» операции типа «set» и «test» не были сделаны «неделимыми» (indivisible), что и привело к наложению друг на друга их «критических секций» и — соответственно — к печальным последствиям.

    Можно выделить и такой фактор, как переоценка уровня безопасности, в принципе гарантируемого программным обеспечением. Это послужило стимулом заменить используемые в предыдущих версиях системы защитные механизмы, которые контролировали радиационные потоки и блокировали их в случае выхода из нормального режима, с «аппаратных» блокираторов (на базе электронно-механических устройств) на чисто программные. Роковую роль сыграло и отсутствие должным образом поставленной системы контроля и исследования природы задокументированных инцидентов, а также некорректные процедуры оценки риска, которые не учитывали специфику ПО. Каждый раз после очередного случая с переоблучением производитель утверждал, что причина выяснена и корректирующие действия предприняты; это не было ложью, но потребовалось два года, чтобы от исправления частностей (которые не делали систему безопаснее) перейти, наконец, к трезвой оценке глобальных особенностей проекта, изменить дисциплину разработки и выполнить корректный анализ рисков.

    Мифы о безопасности ПО

    Катастрофы с Ariane 5 и Therac-25, сами по себе беспрецедентные, конечно же не являются уникальными. Можно привести длинный список больших и малых инцидентов в системах, относящихся к классу mission-critical, произошедших по причине дефектов в программном обеспечении и проявившихся только в режиме эксплуатации. Конечно, большинство инцидентов так или иначе расследовалось и осмыслялось. К сожалению, специфика «ответственных» систем часто такова, что это осмысление не становилось достоянием всего программистского сообщества — поэтому, неудивительно, что в разное время и в разных местах повторялись сходные ошибки. Соответственно, слишком многие приобретают специфические знания и опыт на практике, методом проб и ошибок, которые — как лишний раз показывает разобранные инциденты — обходятся дорого.

    Что же может предложить в этом отношении наука? Только недавно общесистемные и общеинженерные дисциплины «Безопасность Систем» (System Safety) и «Управление Рисками» (Risk Management) начали настраиваться на ту выраженную специфику, которую имеют программно-аппаратные комплексы в контексте их разработки, эксплуатации и сопровождения. Крупнейший специалист в данной области профессор Вашингтонского Университета Нэнси Левесон (Nancy Leveson) ввела даже специальный термин Safeware, который вынесла в название своей книги [7] — пока единственной в мировой литературе, где систематически рассматриваются вопросы безопасности и рисков в компьютерных системах. В частности, в этой книге разбираются некоторые распространенные мифологические представления о ПО и связанных с ним безопасности и рисках, бытующие на фоне все более широкого использования сложных систем в потенциально опасных приложениях. Остановимся на некоторых из них.

    О «дешевом и технологичном» ПО

    Бытует мнение, что стоимость программно-аппаратных систем обычно меньше, чем аналоговых или электромеханических, выполняющих ту же задачу. Однако, это миф, если, конечно, не говорить о «голом» hardware и однажды оплаченном ПО, сработанном «на коленке». Стоимость написания и сертификации действительно надежного ПО очень высока; к тому же необходимо принимать во внимание затраты на сопровождение — опять же такое, которое не подрывает надежности и безопасности. Показательный пример: только сопровождение относительно простого и не очень большого по объему (около 400 тыс. слов) программного обеспечения для бортового компьютера, установленного на американском космическом корабле типа Shuttle, стоит NASA 100 млн. долл. год.

    Следующий миф заключается в том, что ПО при необходимости достаточно просто модифицировать. Однако, и это верно только на поверхностный взгляд. Изменения в программных модулях легко выполнить технически, однако трудно сделать это без внесения новых ошибок. Необходимые для гарантий безопасности верификация и сертификация означают новые большие затраты. К тому же, чем длиннее время жизни программы, тем более возрастает опасность вместе с изменениями внести ошибки — например, потому, что некоторые разработчики с течением времени перестают быть таковыми, а документация редко является исчерпывающей. Оба примера — что с Ariane 5, что с Therac-25 вполне подтверждают эту точку зрения. Между тем, масштабы изменений в ПО могут быть весьма велики. Например, ПО для космических кораблей типа Shuttle [8] за 10 лет сопровождения, начиная с 1980 г., подверглось 14-ти модификациям, приведшим к изменению 152 тысяч слов кода (полный объем ПО — 400 тысяч слов). Необходимость модернизации ПО диктовалась периодическим обновлением аппаратной базы, добавлением функциональности, а также происходило по причине необходимости исправления выявленных дефектов. По оценке независимых экспертов, эти модификации поначалу не сопровождались должными процедурами по поддержке безопасности, однако, случившаяся в 1986 г. авария с кораблем Challenger, которая хотя и произошла по причинам, не связанным с ПО, послужила толчком к пересмотру всей политики NASA в области безопасности, затронув и область ПО.

    Наконец, вряд ли справедливо мнение, что все более входящий в практику принцип повторного использования ПО дает повышенные гарантии безопасности.

    Мысль о том, что использование имеющего длительную историю и уже зарекомендовавшего себя с положительной стороны модуля, равно как и «коробочного» продукта, дает гарантии отсутствия в нем ошибок, весьма естественна с точки зрения «здравого смысла» и способна притупить бдительность. На самом деле повторное использование программных модулей может и понизить безопасность по той простой причине, что данные модули изначально разрабатывались и отлаживались для использования в ином контексте, а спецификация обычно не дает исчерпывающего отчета о всех видах возможного поведения модуля (произошедшая с Ariane 5 авария имеет основной причиной именно повторное использование модуля с некорректной для изменившегося контекста спецификацией).

    В случае с Therac-25 большой вклад в произошедшие инциденты внесли модули, изначально разработанные для предыдущей версии системы (Therac-20) — во всяком случае, было точно установлено, что именно ошибки в этих повторно-используемых модулях вызвали по крайней мере два смертных случая. Причем, эти ошибки (как уже было установлено задним числом) проявлялись и при работе Therac-20, но та система была устроена так, что массивного переоблучения не происходило, а потому и процесс коррекции ошибок не запускался.

    Можно привести еще несколько любопытных иллюстраций к проблемам, связанным с повторным использованием. Так, попытка внедрить в Англии программную систему управления воздушным движением, которая до того несколько лет успешно эксплуатировалась в США, оказалась сопряжена с большими трудностями — ряд модулей весьма оригинальным образом обращались с информацией о географической долготе: карта Англия уподоблялась листу бумаги, согнутому и сложенному вдоль Гринвичского меридиана, и получалось, что симметрично расположенные относительно этого нулевого меридиана населенные пункты накладывались друг на друга. В Америке, через которую нулевой меридиан не проходит, эти проблемы никак не проявлялись. Аналогично, успешно функционировавшее авиационное ПО, изначально написанное с неявным прицелом на эксплуатацию в северном полушарии, создавало проблемы, когда его стали использовать при полетах по другую сторону экватора. Наконец, ПО, написанное для американских истребителей F-16, явилось причиной нескольких инцидентов, будучи использованным израильской авиацией при полетах над Мертвым морем, которое, как известно, находится ниже уровня моря. Это лишний раз подтверждает мысль, что безопасность ПО нельзя оценивать в отрыве от среды, в контексте которой эксплуатируется вся система.

    О «корректном» ПО

    Заветная мечта (не столько программистов, сколько потребителей), чтобы в ПО не было ошибок, увы, никак не исполняется. И иллюзий на этот счет уже не осталось. Соответственно, утверждение, что тестирование ПО и/или «доказательство» его корректности позволяют выявить и исправить все ошибки, можно признать тем мифом, в который мало кто верит.

    Причина очевидна. Прежде всего, исчерпывающее тестирование сложных программных систем невозможно в принципе: реально проверить только небольшую часть из всего пространства возможных состояний программы. В результате, тестирование может продемонстрировать наличие ошибок, но не может дать гарантию, что их нет. Как ядовито замечают Жезекель и Мейер [2], собственно, сам запуск Ariane 5 и явился весьма качественно выполненным тестом; правда, не каждый согласится платить полмиллиарда долларов за обнаружение ошибки переполнения.

    Что же касается использования математических методов для верификации ПО в плане его соответствия спецификации, то оно (несмотря на оптимизм, особенно явный в 70-х г.) пока не вошло в практику в сколько-нибудь значительном масштабе, хотя и сейчас некоторые влиятельные специалисты продолжают утверждать, что это непременно случится в будущем. Вопрос, реалистично ли ожидать, что для систем масштаба Ariane 5 возможно выполнить полный цикл доказательства правильности всего ПО, остается открытым. Нет сомнений, однако, что для отдельных подсистем такая задача может и должна ставиться — уже приводились аргументы о полезности использования формальных методов при разработке механизмов синхронизации в Therac-25.

    Формальные методы разработки — это тема специального большого разговора. Здесь же в качестве примера формального подхода, имеющего промышленные перспективы, упомянем только «B-Method» [9], получивший недавно широкое паблисити в связи с созданием ПО для автоматического управления движением на одной из линий парижского метро. Разработчик метода — Жан-Раймон Абриал (J.-R. Abrial), до того известный как создатель формального метода Z (вошедшего в учебные программы всех уважающих себя университетов), использовал идеи таких классиков, как Эдсгар Дийкстра (E.W.Dijkstra) и Тони Хоар (C.A.R.Hoare). Важно, что основанная на формализмах методология поддержана практической инструментальной средой разработки Atelie B (которая, кстати, не единственная).

    Эта среда включает в себя инструменты для статической верификации написанных на B-коде компонентов и для автоматического выполнения доказательств, автоматические трансляторы из B-кода в Си и Ада, повторно-используемые библиотеки B-компонентов, средства графического представления проектов и генерации документации, гипертекстовый навигатор и аниматор, позволяющий в интерактивном режиме моделировать исполнение проекта из спецификации, и, наконец, средства по управлению проектом. При разработке ПО для метро, включавшего около 100 тысяч строк B-кода (что эквивалентно 87 тыс. строк на Ада) пришлось доказать около 28 тысяч лемм. Насколько этот подход (и аналогичные ему) будет востребован практикой, покажет будущее.

    И все же, такого рода верификация все равно не способна решить все проблемы, в частности, потому, что требуется специфицирование «корректного поведения» программной системы на формальном математическом языке, а это может быть очень непросто. К тому же, источник многих потенциально опасных ошибок может быть не связан непосредственно с вычислительными и алгоритмическими аспектами. Например, в 1992 году большой резонанс получил произошедший в Англии случай, когда «пошел в разнос» компьютер на станции скорой помощи: причина — неожиданно проявившиеся трудности с синхронизацией процессов в условиях большого количества поступивших заявок.

    О «надежном» ПО

    Теперь — о менее очевидном мифе, который звучит так: программно-аппаратные системы обеспечивают заведомо большую надежность по сравнению с теми традиционными (например, электро-механическими) приборами, которые они заменяют.

    Понятно, что аппаратные системы способны выдать случайный сбой, могут неправильно реагировать на изменившиеся условия окружающей среды и со временем изнашиваются. К тому же управление ими критически зависит от «человеческого фактора». А вот программное обеспечение ничему этому вроде бы не подвержено, а значит уже поэтому возложение на него функций, до того реализуемых на аппаратном или «операторном» уровне, уменьшает риски и повышает безопасность. И с этим очень хотелось бы согласиться, вот только рассмотренные частные случаи не позволяют — вероятность систематических проектных ошибок даже в программных разработках, выполняемых высококвалифицированными коллективами для требовательных заказчиков, совсем ненулевая.

    В конце 80-х гг. такая влиятельная в оборонных кругах организация как British Royal Signals and Radar Establishment сделала попытку оценки распространенности дефектов в ПО, написанном для ряда очень ответственных систем. Оказалось, что «до 10% программных модулей и отдельных функций не соответствуют спецификациям в одном или нескольких режимах работы» [7]. Такого рода отклонения были обнаружены даже в ПО, прошедшем полный цикл всестороннего тестирования. Хотя большинство обнаруженных ошибок были признаны слишком незначительными, чтобы вызвать сколь-либо серьезные последствия, все же 5% функций могли оказывать разного рода значимое негативное воздействие на поведение всей системы. Примечательно, что среди прочего авторы исследования особо упомянули выявленную в одном из модулей неназванной системы потенциальную возможность переполнения в целой арифметике, что могло привести к выдаче команды приводу повернуть некую установку не направо (как следовало), а налево. Достаточно предположить, что речь в ПО шла об управлении ориентацией пусковой ракетной установки, чтобы представить возможные последствия.

    Коварство программных ошибок и в том, что они могут проявиться далеко не сразу, иногда после сотен тысяч часов нормальной эксплуатации — как реакция на вдруг возникшую специфическую комбинацию многочисленных факторов. Так, установка Therac-25 вполне корректно работала в течение нескольких лет до первого переоблучения; и последующие зафиксированные инциденты происходили спорадически в течение 2.5 лет на общем «нормальном» фоне. NASA инвестировала огромные средства и ресурсы в верификацию и сопровождение программного обеспечения для космических кораблей Shuttle. Несмотря на это, за 10-летие с 1980 г. — времени начала использования ПО — выявлено 16 ошибок «первой степени серьезности» (способных привести к «потере корабля и/или экипажа»). Восемь из этих ошибок не были обнаружены своевременно и присутствовали в коде во время полетов, хотя, к счастью, без последствий. Зато во время полетов были задокументированы проблемы, возникшие от проявившихся 12 значимых ошибок, из которых три относились ко «второй степени серьезности» («препятствуют выполнению критически важных задач полета»). А ведь NASA имеет, может быть, самую совершенную и дорогостоящую комплексную систему процессов разработки и верификации ПО.

    В то время как надежность аппаратуры может быть увеличена за счет ее дублирования, что резко нивелирует опасности от случайных сбоев, эквивалентного способа защиты от систематических программных ошибок не найдено (даже если некоторые вендоры, с подачи оторванных от практики исследователей, рекламируют методики и инструментарий, позволяющие разрабатывать «zero-defect software»). Впрочем, если бы методы производства идеального ПО существовали, то резонно предположить, что следование им потребовало бы нереалистично большого количества ресурсов и времени. Повсеместно, в том числе и при создании ответственных систем, наблюдаемая тенденция свидетельствует о движении в обратном направлении — в сторону снижения издержек, и стоимостных, и временных.

    Наконец, как ни парадоксально это звучит, даже если бы компьютерные системы действительно были надежнее «традиционных», то это вовсе не обязательно означает, что они обеспечивают большую безопасность. Дело в том, что надежность ПО традиционно определяется степенью его соответствия зафиксированным в спецификациях требованиям; однако, часто бывает так, что ПО делает именно то, что ему и было предписано, и авария Ariane 5 — классический тому пример: и злополучное вычисление посторонней для полета величины горизонтального отклонения Инерциальной Платформы, и реакция на него вплоть до выведения из строя всех навигационных систем и бортовых компьютеров — все это случилось в полном соответствии с Требованиями, которые были частично унаследованы от Ariane 4 и не отражали новых реальностей. Более того, по сравнению с ошибками в коде именно спецификационные ошибки обычно ведут к более тяжелым последствиям — компетенции разработчиков ПО недостаточно для обнаружения таких ошибок. Программный комплекс — сложная система, однако реальный мир, отражаемый в спецификационных требованиях — еще более сложен и требует специальных экспертных знаний. Так что надежность ПО и его безопасность — понятия, хотя и перекрывающиеся, но не идентичные.

    Фактически любая сложная программная система при определенных обстоятельствах способна вести себя неожиданно для разработчиков и/или пользователей. Вероятность такого поведения, особенно если оно может привести к тяжелым последствиям, следует реалистически оценивать и предусматривать специальные средства защиты, в том числе — уже не на уровне самого ПО, а на уровне всей системы. Собственно, авария с Ariane 5 продемонстрировала это в полной мере: реагируй система на выброшенное исключение не столь радикально, аварии бы не произошло — ведь сам полет проходил нормально, но этот «глобальный контекст» просто не принимался во внимание!

    Аналогично, катастрофические последствия при использовании Therac-25 наступили не столько из-за ошибок, допущенных в ПО, сколько вследствие того, что на аппаратном уровне не было предусмотрено защиты против этих ошибок. Шлейф программных ошибок тянулся к Therac-25 от ранних версий этого сложного программно-аппаратного комплекса, но в предыдущей модели Therac-20 надлежащие аппаратные защитные механизмы были задействованы — от них отказались по соображениям достижения большей производительности. К тому же программных ошибок оказалось много: в каждом конкретном инциденте проявлялась одна из них, ее исправляли — затем следующий инцидент (уже со смертельным исходом) показывал, что исправлено не все. Безопасность — это свойство всей системы, а не только ее программного компонента.

    Эпитафия

    Очевидный урок: приводящие к катастрофическим последствиям дефекты в ПО являются результатом пренебрежения хорошо структурированными и стандартизованными инженерными методами и технологиями, которые, впрочем, должны применяться в контексте контроля всех аспектов разработки и функционирования ответственных систем, включая «человеческий фактор». К сожалению, далеко не всем понятно, что разработка программно-аппаратных систем — это именно инженерный процесс, требующий продуманной и поставленной технологии и опирающийся на исполнителей высокой квалификации. Об этом не устают напоминать классики (например, Никлаус Вирт [10]), но слышат ли их?

    На наших глазах повышается сложность программно-аппаратных систем, традиционно не относящихся к разряду mission-critical. Не за горами время, когда на массовый потребительский рынок начнут поступать программные комплексы, дефекты в которых могут оказаться крайне неприятными для неготовых к принятию риска «простых» граждан. В конце концов, даже обычный утюг способен вызвать пожар и наверное, какой-нибудь программно-управляемый супер-кухонный-комбайн XXI века может (при ПО надлежащего «качества») повести себя неожиданно (а то и опасно) для домохозяйки.

    Между тем, сегодня на массовом рынке программных продуктов стандарты качества сознательно занижены (о чем мне уже доводилось писать применительно к производственной культуре Microsoft [11]). Торжествует «good enough software», когда критерии качества не имеют столь высокого приоритета, как удобство пользования, простота освоения и дешевизна — и все это в сочетании с избыточной функциональностью, пожирающей компьютерные ресурсы, и отсутствием у производителя стимула выбрасывать на рынок действительно отлаженный продукт. Весьма взрывчатая смесь. В обозримом будущем мы можем оказаться свидетелями катастрофических ситуаций, в которые попадут пользователи массовых продуктов, и, похоже, что только это способно сдвинуть ситуацию с ее нынешнего печального положения.

    К тому же, функционирующий в соответствии с законами «массовой культуры» рынок обрастает глашатаями того же розлива, обслуживающими тех, кто заказывает музыку. Как и положено в шоу-бизнесе, музыка играет громко и агрессивно. К сожалению, именно в России, по сравнению с западными странами, нарушен баланс между «популярной» компьютерной периодикой и той, что ориентирована на программистов-профессионалов, которым не так просто найти материалы, полезные для совершенствования. В результате размываются критерии, и энтузиасты (которых можно, в зависимости от точки зрения отнести и к «хакерам», и к «чайникам»), освоившие какой-нибудь новомодный инструмент «за 21 день», считают себя готовыми к серьезной работе. А если найдутся менеджеры того же пошиба, которые им эту работу действительно доверят?

    Небезынтересно в этом контексте упомянуть, что та же Microsoft пытается проникнуть на рынок «ответственных» систем; во всяком случае, она не прочь получить подряд на поставку большой партии Window NT для федеральных организаций, чья работа завязана на «обеспечение национальной безопасности». А для этого надо сертифицировать эту ОС на соответсвие одному из базовых уровней безопасности компьютерных систем С2 (в соответствии с критериями, определенными в «Оранжевой книге» Агенства Национальной Безопасности США). Хотелось бы, конечно, надеяться, что осваивая сегмент рынка с принципиально иными требованиями к продуктам, производители массового ПО поднимут планку качества и в своей традиционной вотчине. А ну как окажется наоборот?

    И последнее. Все примеры в данной статье относятся к зарубежным системам. В России всегда была очень мощная отрасль mission-critical систем, выглядевшая вполне конкурентоспособно на общем мировом фоне. Отрадно, что и в нынешние турбулентные времена еще сохранились работоспособные коллективы. Однако с авариями самых разных видов и масштабов в России недостатка тоже никогда не было. Например, можно вспомнить о нескольких не столь давних авариях при пусках ракет — носителей, внешне очень похожих на катастрофу Ariane 5, да и произошедших примерно в то же время. Что нам известно об их причинах?

    Эпилог

    Что касается Therac-25, то после выполненной-таки в 1988 году капитальной ревизии комплекса и коррекции ряда проектных и реализационных решений, ни о каких новых инцидентах не сообщалось.

    Первый после аварии запуск Ariane 5 несколько раз откладывался и состоялся 30 октября 1997 г. Между тем, летопись катастроф при запусках ракет продолжала пополняться. Так, в августе 1998 г. взорвались при старте ракета Titan-4 (производства Lockheed Martin), выводившая на орбиту американский шпионский спутник (стоимость аварии оценена в 1.2 млрд. долл.), а неделей позже — ракета Delta-3 (производитель — Boeing), убытки — «всего» 225 млн. долл. В начале сентября та же судьба постигла украинскую ракету Зенит, стартовавшую с Байконура. Виновато ли в этих авариях ПО? Может быть, может быть?

    Литература

    1. Jacques-Louis Lions, Доклад комиссии, ESA, CNES.
    2. J.-M. Jezequel, B. Meyer «Put It in the Contract: The Lessons of Ariane», // Computer, Vol.30, No.2, January 1997, pp.129-130.
    3. Бертран Мейер, «Построение надежного объектно-ориентированного ПО. Введение в Контрактное Проектирование», //Открытые системы, №6, 1998.
    4. K. Garlington, «Critique of «Put it in the Contract: The Lessons of Ariane», March 1998
    5. B. Nuseibeh, «Ariane 5: Who Dunnit?», //IEEE Software, Vol.14, No.3, 1997, pp.15-16.
    6. N. Leveson, C. Turner «An Investigation of the Therac-25 Accidents», — Computer, Vol.26, N.7, July 1993, p. 18-41.
    7. N. Leveson, «Safeware: System Safety and Computers», — Addison-Wesley, 1995
    8. «An Assessment of Space Shuttle Flight Software Development processes», — Committee for Review of Ovеrsight Mechanisms for Space Shuttle Flight Software Development Processes, National Research Council, 1993
    9. J.-R. Abrial, «The B-Book: Assigning Programs to Meanings», //Cambridge University Press, 1996
    10. Карло Пешио, «Никлаус Вирт о Культуре Разработки ПО», //Открытые системы, №1, 1998, сc.41-44,
    11. Валерий Аджиев, «MS: Корпоративная Культура Разработки ПО», //Открытые системы, №1, 1998, с.45-51. 

    Валерий Аджиев (valchess@gmail.com).

    Баг — ошибка в программе или системе, из-за которой программа выдает неожиданное и непредсказуемое поведение и, как следствие, результат. Первый баг был зафиксирован 9 сентября 1945 года: в вычислительной машине Mark II Aiken Relay Calculator нашли мотылька, застрявшего между контактами электромеханического реле, что приводило к ошибкам. Извлеченное насекомое было вклеено в технический дневник с сопроводительной надписью: «First actual case of bug being found». Этот забавный факт и положил начало использованию слова «баг» в современном значении. 

    Падение телефонной сети AT&T

    15 января 1990 года ошибка в новой версии прошивки междугородних коммутаторов привела к тому, что в один прекрасный день 114 соседних коммутаторов перестали работать, и в следствие этого более 60 тысяч человек остались без междугородней связи на 9 часов. Согласно программе, коммутатор должен перезагрузиться, если получит соответствующий сигнал, однако он по ошибке рассылался каждый раз при восстановлении после сбоя какого-либо коммутатора. Все началось с падения и перезагрузки коммутатора в Нью-Йорке, который вызвал масштабную цепную реакцию, в результате которой 114 коммутаторов перезагружались непрерывно каждые 6 секунд. Сначала компания обвиняла хакеров, однако позже выяснилось, что причиной стала одна ошибочная строка кода, в которой реализовывалась отправка неверного сигнала.

    Запуск ракеты Mariner I

    В 1962 году ракета с космическим зондом Mariner-1, который должен был отправиться к Венере, вскоре после запуска отклонилась от намеченной траектории полета. Через 293 секунды был отдан приказ уничтожить ракету над Атлантическим океаном. Никто не погиб, однако экономические потери составили 18.3 миллиона долларов. Программист сделал ошибку, когда переводил рукописные математические формулы в код. Символ логического отрицания он принял за минус, и это привело к тому, что ракета воспринимала нормальные скорости как критические и из-за этого сбилась с курса. На будущее совет: внимательно переписывайте рукописный текст.

    Аппарат лучевой терапии Therac-25

    В 1985 году эта модель аппарата лишила жизни двух человек, и еще четверо получили серьезное облучение. Ошибка крылась в программном управлении защитой от облучения, которая считалась более надежной, чем электромеханическая. Известно, что неисправность была вызвана тем, что в проекте использовались библиотеки с ошибками, входящие в состав ПО аппарата Therac-20, что и привело к фатальным последствиям. В коде была найдена довольно распространенная ошибка многопоточности, называемое состоянием гонки. Тем не менее ошибку не заметили, так как Therac-20 работал исправно из-за дополнительных мер предосторожности. Не зря вопрос про состояние гонки — один из самых задаваемых на собеседовании вопросов по многопоточности, ведь он приносит так много хлопот. Рекомендуем почитать подробнее про эту ошибку.

    Взрыв ракеты Ariane 5

    В 1996 году ракета Ariane 5, на борту которой были 4 научных спутника, взорвалась через 36.7 секунд после взлета. Это тот случай, когда банальная ошибка переполнения переменной нанесла ущерб в 7 миллиардов долларов. При разработке системы управления ракетой были использованы некоторые части кода от ПО Ariane 4, однако у Ariane 5 показатели скорости были несколько больше, что и вызвало переполнение переменной. Ошибки можно было избежать, если бы при использовании ПО от другого оборудования не забыли подправить код. Видео, запечатлевшее аварию:

    Массовое отключение электроэнергии в США и Канаде

    В 2003 году состояние гонки в ПО системы управления электростанцией вызвала прекращение подачи электроэнергии и 55 миллионов человек лишились электроснабжения. Деревья, которые находятся под линиями электропередач, регулярно подстригают, однако в Кливленде этого не сделали. Вследствие жары и увеличения энергопотребления провода провисли ниже обычного и коснулись деревьев: случилось замыкание, и электростанция в Кливленде вышла из строя. Аварийная система не предупредила персонал о перегрузках в сети, поэтому произошло каскадное отключение еще около сотни электростанций. В ходе расследования установили, как такое произошло: состояние гонки вызывало подвисание сигнализации в комнате персонала на целый час, поэтому сотрудники электростанции не получали никаких сигналов о том, что произошла беда.

    Баги хоть и являются вполне обычным делом в жизни программиста, однако некоторые из них способны нанести огромное количество ущерба и даже унести жизни. Так что учитесь на чужих ошибках и будьте очень внимательны!

    Источники: Wired.com, Wikipedia.org

    Понравилась статья? Поделить с друзьями:
  • The witcher 2 assassins of kings ошибка mfc100u
  • The windows server failover clustering wsfc resource control api returned error code 5057
  • The windows schannel error state is 1205
  • The windows schannel error state is 1203
  • The windows installer service could not be accessed hamachi windows 10 как исправить