Когда пристёгиваешь пациента к электронной пушке, способной выстреливать пучком частиц с энергией 25 МэВ, следование процедурам — вопрос жизни и смерти. Оператор, эксплуатировавшая аппарат лучевой терапии в Онкологическом центре Восточного Техаса (East Texas Cancer Center, ETCC), работала с ним достаточно долго для того, чтобы запомнить весь процесс.

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

Therac 25 54.gif

Правильно уложив пациента, она снова повернула поворотный диск. У него было ещё два режима: один позиционировал массив магнитов между пучком и пациентом; магниты должны формировать и нацеливать пучок; второй помещал кусок металла между пучком и пациентом. При подаче пучка электронов мощностью 25 МэВ на металл он создаёт рентгеновское излучение.

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

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

Оператор выполняла этот процесс так много раз, что научилась вводить направление очень быстро, по крайней мере, на этом устройстве. Возможно, даже слишком быстро. В поле типа пучка она случайно ввела «X» (от «x-ray», рентгеновские лучи). Ошибка была естественной, ведь большинство пациентов подвергалось рентгеновскому лечению, и особой проблемы не представляла: компьютер увидел бы, что поворотный диск находится не в том положении, и отказался облучать пациента дозой. Оператор быстро нажала на клавишу «вверх» на клавиатуре, чтобы вернуться к полю, изменила значение на «E» («electron») и подтвердила ввод всех остальных параметров.

Её палец навис над клавишей «B», пока она проверяла правильность ввода даты. Убедившись, что всё правильно, она нажала на «B» («beam start», «запустить пучок»). Не раздалось никакого шума, впрочем, как и всегда, но спустя секунду на терминале высветилось «Malfunction 54» («Неисправность 54»), а затем «Treatment Pause» («Процедура приостановлена»).

Ошибки никого не удивляли. Рядом с консолью у оператора висела таблица со всеми кодами ошибок. В данном случае, «Malfunction 54» означало ошибку «dose input 2» («ввод 2 дозы»).

Возможно, это ничего не объясняло, но оператор привыкла к загадочности кодов ошибок. А «процедура приостановлена» означало, что следует продолжить процедуру. Согласно информации на терминале, излучение ещё не подавалось, поэтому она нажала клавишу «P», чтобы снять пучок с паузы.

А потом она услышала крик.

У пациента уже было несколько таких сеансов, и он знал, что ничего не должен почувствовать. Однако когда оператор активировала пучок в первый раз, он ощутил жжение, которое позже сравнил с «горячим кофе», пролитым ему на спину. Без интеркома он не мог позвать на помощь, поэтому начал слезать с процедурного стола. Он всё ещё сползал, крича о помощи, когда оператор сняла пучок с паузы; при этом он испытал нечто, похожее на сильнейший удар электрическим током.

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

Пациенту прописали дозу в 180 рад в рамках шестинедельной программы лечения, в течение которой он суммарно получил бы шесть тысяч рад. Согласно показаниям Therac-25, пациент получил недостаточную дозу, небольшую долю этого излучения. Никто ещё не знал, что неисправность привела к подаче примерно 16-25 тысяч рад. Казалось, с пациентом всё в порядке, но на самом деле он был мёртв, просто никто этого ещё не знал.


Инцидент в ETCC был не первой и, к сожалению, не последней неисправностью системы Therac-25. В период с июня 1985 года по июль 1987 года произошло шесть инцидентов с аппаратом Therac-25, изготовленным компанией Atomic Energy Canada Limited (AECL). Каждый завершился сильной передозировкой радиации, что привело к серьёзным травмам, увечьям и смертям.

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

Спустя несколько недель в ETCC произошёл второй случай передозировки, и примерно в то же время этой ситуацией заинтересовалось Управление по санитарному надзору за качеством пищевых продуктов и медикаментов США, а также пресса. Поначалу было множество гипотез о причинах инцидентов. Любопытен следующий комментарий из списка рассылки RISKS за 1986 год.

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

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


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

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

Однако AECL была уверена в этом ПО, потому что оно не было новым. Первые версии ПО были разработаны ещё для Therac-6. Разработка началась в 1972 году, а в 1976 году программы были адаптированы под Therac-25. То же самое ядро применялось и в Therac-20. AECL считала, что ПО должно быть безопасным, ведь им пользовались уже долгое время.

На самом деле, когда AECL проводила собственный внутренний анализ безопасности Therac-25 в 1983 году, компания исходила их следующих допущений:

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

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


После второго инцидента в ETCC дозиметрист больницы вывел Therac-25 из эксплуатации и совместно с оператором приступил к воссозданию действий, которые привели к передозировке. Вызвать сообщение об ошибке «Malfunction 54» было непросто, особенно при методических попытках воссоздания конкретных действий, потому что, как оказалось, если вводить данные медленно, проблемы не возникают.

Для передозировки необходимо было вводить данные быстро, со скоростью опытного оператора. Дозиметрист практиковался, пока не смог воссоздать ошибку, а затем сообщил о своих результатах AECL. Пока он замерял величины передозировок, AECL ответила ему: компания сообщила, что не может воссоздать ошибку. По сути, она сказала «на моём компьютере всё работает».

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

Имея эту информацию, стало проще выявить первопричину: это было состояние гонки. Когда оператор ошибочно ввела «X» (x-ray), компьютер вычислял последовательность активации пучка для подачи высокоэнергетического пучка с целью генерации рентгеновского излучения. Когда оператор нажала на клавишу «вверх», чтобы исправить свою ошибку, это должно было привести к пересчёту последовательности активации, но если пользователь выполнял ввод слишком быстро, то UI обновлялся, однако пересчёт не происходил.


В середине 1986 года в ситуацию вмешалось Управление по санитарному надзору за качеством пищевых продуктов и медикаментов (Food and Drug Administration, FDA) и потребовало, чтобы AECL разработала и внедрила план корректирующих мероприятий (Corrective Action Plan, CAP). Далее последовал длительный процесс внесения поправок: AECL присылала свой CAP, после чего FDA задавала вопросы, приводившие к новым поправкам в CAP.

Например, FDA проверило первую версию CAP и отметило, что она неполная. В частности, в него не был включён план испытаний. AECL ответила так:

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

FDA это не понравилось, и после переписки оно ответило следующим образом:

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

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

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

AECL устранила этот баг (код перестал выполнять инкремент и теперь просто задавал значение) и дополнила CAP. Управление FDA признало, что это, вероятно, предотвратит возникновение проблемы, но всё равно не было убеждено полностью. Цитата из внутреннего документа:

Мы заявляем: можно считать, что предложенный CAP устранит недостатки, для ликвидации которых он был разработан. Однако мы не можем сказать, что полностью уверены в безопасности системы в целом…

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

В процессе проверки результатов испытаний FDA отметило следующее:

Удивительно, что тестовые данные, представленные для доказательства того, что изменения в ПО для решения проблем с редактированием в интерфейсе Therac-25 реализованы правильно, показывают обратное… Я могу лишь предположить, что исправленная версия некорректна или что данные введены неправильно.


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

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

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

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

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

Сбои в ИТ редко оказываются личными неудачами. Это сбои процессов, систематические и организационные сбои. История AECL и Therac-25 показывает, насколько плохо могут окончиться организационные недосмотры.

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

Инцидент с Therac-25 — уже древняя история, но с тех пор ПО стало ещё важнее для мира. Мы надеемся, что критичное для безопасности ПО разрабатывается по строгим процедурам, но знаем, что это не всегда так. Относительно недавним примером стали катастрофы Boeing 737MAX. Но, учитывая важность ПО в современном мире, даже более тривиальные программные проблемы могут принимать огромный масштаб. Машинное обучение, усиливающее расовые предрассудки, социальные сети, превращающиеся в источники дезинформации, плохо защищённые IoT-устройства, становящиеся ботнетами — всё это свидетельства того, как ПО взаимодействует с миром и влияет на него.

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


Давайте ненадолго вернёмся к состоянию гонки, ставшему причиной инцидентов в ETCC. Оно возникло из-за того, что пользователи слишком быстро нажимали на клавишу «вверх», и система не успевала правильно зарегистрировать внесённые изменения. Пока продолжался процесс согласования CAP с FDA, компания AECL хотела обеспечить безопасную эксплуатацию Therac-25, поэтому публиковала исправления, которые пользователи должны были применять в своих аппаратах.

Вот письмо, которое AECL разослала с целью устранения этого бага:

ТЕМА: ИЗМЕНЕНИЯ В ПРОЦЕДУРАХ ЭКСПЛУАТАЦИИ ЛИНЕЙНОГО УСКОРИТЕЛЯ THERAC-25
С этого момента и до дальнейшего уведомления клавишу, используемую для перемещения курсора обратно при вводе направления (то есть клавишу курсора «вверх» с нарисованной на ней стрелкой вверх) не допускается использовать для редактирования и любых других целей.
Чтобы избежать случайного нажатия на эту клавишу, следует снять клавишный колпачок и при помощи изоляционной ленты или иного изолирующего материала зафиксировать контакты в открытом положении.
За помощью в реализации последнего следует обратиться к местному представителю технической поддержки AECL.
При отключении этой клавиши в случае ввода любых некорректных данных направления следует использовать команду сброса «R» и вводить направление повторно.
В случае использования опции Multiport это также означает, что между портами будет невозможно редактировать мощность дозы, дозировку и время.

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


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

Комментарии (8)


  1. AlexXYZ
    01.09.2025 13:31

    1. Неужели было трудно поставить датчик измерения на выходе, который моментально отключал бы оборудование, если оно выдаёт количество излучения, которое, очевидно, будет представлять угрозу для пациента?

    2. Обработка ошибок - это прямо домоклов меч программирования во все времена. Программист считает, что пользователь не может ошибиться, а пользователь считает, что программа всё проверяет.


    1. AbitLogic
      01.09.2025 13:31

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

      2. Rust решает эту проблему, он заставляет явно обработать ошибки программиста, а не надеяться на когда-нибудь потом, состояние гонки там можно получить только умышленно и надо очень постараться


    1. mayorovp
      01.09.2025 13:31

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

      Состояния гонок - вот истинный дамоклов меч.


    1. iiwabor
      01.09.2025 13:31

      Там была проверяющая система, но она, как потом выяснилось, тоже работала некорректно.

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

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


  1. uranik
    01.09.2025 13:31

    Могли бы кнопку "submit" на форму добавить и отправлять все значения оптом на сервер.


    1. kipar
      01.09.2025 13:31

      Сервера там не было, один микрокомпьютер и программа на ассемблере. А ошибок там нашли кучу (https://ru.wikipedia.org/wiki/Therac-25#Замеченные_ошибки). Самая главная, на мой взгляд - то что убрали аппаратные цепи безопасности которые были на Therac-20.


  1. baldr
    01.09.2025 13:31

    Я работаю в IT и это причина, по которой в моём доме:
    - механические замки
    - механические окна
    - роутеры на OpenWrt
    - никакого дерьма вроде умного дома
    - никакой Алексы, никакого Гугл-Ассистента
    - никакого регулирования температуры через интернет

    Самая технологичная вещь в моём доме - это принтер из 2004 и я всегда держу рядом заряженный пистолет на случай, если он издаст какой-нибудь непонятный звук.

    Старый анекдот


  1. iiwabor
    01.09.2025 13:31

    С этой машиной была куча проблем:

    • race condition. В случае с Therac-25 использовалась одна и та же переменная для двух команд, которые могли выполняться в произвольном порядке, что для описываемого аппарата неприемлемо.

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

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

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

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

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

    А главная проблема была как всегда - деньги и время на разработку нового оборудования!

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