Pull to refresh

Comments 95

UFO just landed and posted this here

Хмм, в общем-то да, однако "выход из строя модуля не должен приводить к отказу системы в целом" тоже можно худо бедно програмно гарантировать:


-- Do_Some_Main_Thing --
--
function Do_Some_Main_Thing return ... is
  ...
begin
  ...
exception
  when Exception_1 | Exception_2 => -- возможные ожидаемые исключения
    ...
  when others => -- любые другие исключения (также анонимные) обрабатываются здесь
    Try_Recovery;
end Do_Some_Main_Thing;

-- Try_Recovery --
--
function Try_Recovery return ... is
  ...
begin
  Notify_Engineer; -- неожиданное исключение ...
  ... -- пробуем чего-то-там восстановить, например 
exception
  when others => -- восстановить не удалось
    Notify_Engineer;
    Abandon_Call;
    raise Emergency_Program;
end Try_Recovery;

Как правило в этом случае не критичные модули (как раз наш случай) либо уходят в "спячку" (если например реализовано event-driven) либо кидают уже ожидаемое исключение...


Грубо говоря если мне к примеру 10-й датчик высоты не сообщает текущее состояние, рассчитываем траекторию по средним значениям вычисляемым по другим параметрам для чрезвычайных ситуаций (emergency_program).


Соответственно три важных момента:


  • в программе не должно быть блоков пробрасывающих неожиданное исключение наверх стека исполнения (от слова совсем);
  • в идеале всегда должна быть соответствующая (или хотя бы какая-нибудь) реакция на исключение Emergency_Program;
  • все модули должны быть оттестированы дополнительным бросанием неожиданного исключения (типа Test_Emergency_Unexpected_Error) из любой (т.е. каждой) функции.

А так-то да, неполное покрытие кода тестами — есть тикающая бомба замедленного действия. Таких программистов называют — подрывник...

Насколько я понял в тех условиях, для которых программно-аппаратный комплекс создавался изначально, выход из строя этого модуля был невозможен, это было обосновано математически, и он сознательно не был защищен. Проблема возникла когда старая система была без тестирования перенесена в новое окружение, что и вызвало крах. Даже по нынешним временам со всеми паттернами, статанализами, и маниакальным защитным программированием, нет-нет, да что-нибудь грохнется при миграции, а это же были теплые и ламповые времнеа, когда каждый байт был на счету…
Что-то мне кажется, что в космической индустрии и сейчас «теплые ламповые времена» и «каждый байт на счету»
Но инструментарий все же побогаче.
Однозначно, но все же к размеру кода относятся серьезно
Я имел ввиду, что «тогда» возможности для тестирования всего и вся были куда более ограниченны, нежели сейчас, а так как и сейчас безбажная миграция/интеграция является скорее светлой мечтой, нежели обычным вторником, то говорить, что «тестирование влияния этого программного модуля в случае отказа на работоспособность всей системы в целом не проводилось», наверное, слишком самонадеянно. А может и не самонадеянно, черт его знает, кто там на чем решил сэкономить…
и он сознательно не был защищен

Глупость это и позерство...


а это же были теплые и ламповые времнеа, когда каждый байт был на счету…

Где? В ESA? На спичках тестовом покрытии экономить байты?

Глупость это и позерство...

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

Уверенность эта была подкреплена расчетами, показывающими, что ...


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

А проверить эти условия? Хотя бы минимальный тест-кейс который Notify_Engineer или assert какой бросает, нет, не слышал...


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


Тест же — он тест и есть — автоматически имеем BOOM на новых исходных параметрах (другая траектория, более высокая начальная скорость).


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

В статье сказано, что это сознательный шаг, для снижение вычислительной нагрузки.
Просто пихать проверки на всё и вся — это паранойя :) Есть разумный баланс.
if ( cos(x) > 1 )…
что это сознательный шаг, для снижение вычислительной нагрузки.

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


Просто пихать проверки на всё и вся — это паранойя :) Есть разумный баланс.

Не в проектах стоимостью сотни мильенов вечнорастущих.


if ( cos(x) > 1 )…

Вот только не надо утрировать пжлста...

Ну на самом деле не всё так плохо в NASA, более того у них есть чему поучиться, даже несмотря на такую эпическую ошибку. Причём НАСА особо и не скрывает как ведётся разработка. Ну вот почитайте, к примеру NASA Software Safety Guidebook.

Всебы ничего, только это ESA ;)


И я не говорю, что все из вон рук плохо… Местами… Бывало… Да и сейчас еще...

Упс, а ведь я до сегодняшнего дня был уверен, что это был совместный проект, и НАСА там тоже руку приложило, собственно и в документе, что я выше ссылку дал, эта ракета упоминается. Спасибо за поправку.
НАСА сама делает ошибки похуже. Последний провал — метры в фунты забыли перевести.
Юнит тесты никто упорно не пишет
if ( cos(x) > 1 )…

Вот только не надо утрировать пжлста...

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

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

Дык я не за то вовсе… На тестовом стенде — это очень редко обязательное условие… Это раз. Ну и два, начальные и пограничные условия использования модуля можно же проверить и не "в реальном времени".


Попытаюсь объяснить на пальцах:


Было (из вещей интересующих разраба):


  • железка (модуль, контроллер и т.п.)
  • дока, содержащая примеры кода (схемы, API, и т.п.)

В этом списке (по хорошему) отсутствует один пункт:


  • test-cases (которые как минимум проверяют условия использования железки, т.е. те же траекторию, начальную скорость и т.д. и т.п.) Не путайте с real-time, т.е. чтобы "время исполнения кода не вылезало за жестко поставленные рамки"…

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


Хотя как test-case обертка увеличивает время исполнения кода настолько, что он становится совсем неюзабелен — это то же нонсенс. Тогда получается что и API модуля нельзя использовать… чтобы значит "не вылезало за жестко поставленные рамки". Смысл в том модуле тогда?


Поэтому повторюсь: косяк обоих...


  • у разрабов модуля нет тест-кейсов, как минимум проверяющих "условия использования"
  • у разрабов, использующих готовый модуль, нет тест-кейсов, которые обязаны были словить как минимум это исключение на новых условиях (в реальном времени на тестовом стенде)...

Ну и сам "flow" немного странен, ибо как реагировать на неожиданные исключения учат в школе есть азы изучения той же ada (и моветон забыть или наплевать на такое).


Принцип я коротко коментировал выше.

Возможно там были тест-кейсы, но код их успешно проходил так-как они специально не проверяли эту ошибку — по расчётам этого просто не могло быть! Тому, кто этот код писал, было прекрасно известно, что он выдаст ошибку на высоких скоростях, но их не должно было быть. И всё время, пока код использовался на проекте для которого он был разработан, проблемы не было. Смысл в том, что старый код переиспользовали на новом проекте без подгонки каких-либо тестов на любом этапе под параметры нового проекта. Я вообще сомневаюсь, что этот код кто-то трогал с тех пор. Классический такой легаси. Такое впечатление, что никто не удосужился собрать стенд и прогнать систему по симуляции запуска, подставляя на вход ожидаемые в реальном запуске параметры. А ведь в теории они должны были сделать как минимум это, причём ещё и не раз. Просто потому, что проблема всплыла бы на первой же симуляции.
UFO just landed and posted this here
Если б этот модуль хоть кто-то удосужился бы протестировать с новыми входными данными это бы всплыло и было так или иначе исправлено. В том-то и дело, что с новыми данными этот модуль никто не тестировал в принципе и не важно хочется в это верить или нет, факт остаётся фактом — это было бы исправлено если бы хоть раз было проверено в новых условиях эксплуатации.
ошибка у них была все-таки в системном проектировании и управлении качеством, а не в коде.


Не совсем так. Ошибка в коде, конечно, была (плохая обработка исключительной ситуации — это ошибка). Другое дело, что при современных подходах к коммерческой разработке ПО ошибки в коде принято рассматривать не как ОШИБКИ, а как допуски. Ну вот токарный станок делает шайбы с допуском в 0.1мм, а иногда получаются с допуском в 0.2мм — это никого не смущает, просто есть контроль качества и плохие шайбы выкидывают или допиливают напильником. Так же и с ошибками в коде: ну ладно, забыл программист на null проверить, подумаешь. Тестировщики нашли, программист поправил, продукт зарелизили, все довольны. Вот если тестировщики не нашли — вот это уже проблема: это значит что либо плохо тестировали, либо плохо объяснили тестировщикам требования, против которых надо тестировать, либо изначально требования не так сформулировали… короче да, с точки зрения современной софтверной индустрии — проблема в процессе / управлении качеством.

А вот какие подходы к управлению разработкой / управлению качеством в космической отрасли, тем более какими они были в бородатом 1996 — я не знаю; допускаю, что по меркам современной софтверной индустрии подходы дедовские, т.к. отрасль скорее всего очень консервативная. Если там, как в древнем софтостроении (или как в мелких стартапах сегодня) — «тестировщики? какие тестировщики?» — то ответственность за соответствие софта требованиям лежит только на программистах, т.к. больше просто не на ком.
UFO just landed and posted this here
Просто тогда не было еще PVS Studio.
Кстати интересно, а где-то вообще можно найти исходники прог, применявшихся в космических программах?
Сразу нашлись исходники Apollo-11 с комментариями
https://github.com/chrislgarry/Apollo-11
Всё нормально, угробили кучу денег, допустив просчет в архитектуре, чтобы дали ещё.
Однако, модуль повторно использовался без каких-либо модификаций.

Вот тебе и следствие идеологии «Работает — не трогай».

Дык не столько плохо, что он использовался, сколько то, что не было common-теста в новой связке и с новыми исходными (другая траектория, более высокая начальная скорость)...


Детская ошибка-то, ей богу.

Думаю пока ИИ не возьмётся за создание вычислительных систем, так и будут ошибки-аварии — человеческий фактор, в общем.
Никогда не понимал, как можно экономить на гвоздях в таких проектах, просто тупо перетаскивая модули из одной версии в другую.
Да как так вообще, из-за «васи пупкина», который обломился сверить ТТХ старой и новой платформы происходит «такое».
Кстати, не исключен вариант саботажа, т.е. эти спутники в принципе не должны были попасть на орбиту по 100500 причинам: экономические(выбить еще денег на следующий такой проект + увеличить бюджет на безопасность), политические(nocomment) и прочие.
ИИ не устает, у ИИ нет рассеянности внимания, как у живого человека. Но почему Вы уверены, что все же ИИ не будет допускать ошибок из-за неправильно заложенных параметров при его создании?
Потому что перед вводом в эксплуатацию ИИ можно прогнать через тесты со всеми мыслимыми и немыслимыми параметрами, да это время, да это деньги, но оно того стоит.
Кажется этому почти не учат — анализу ошибок среды, то есть исполнению отлаженного кода в новой для него программно-технической среды.

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

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


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

То же самое на Фукусиме

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

Электроснабжение необходимо для отвода остаточного тепловыделения реакторов, которое, согласно формуле Вэя — Вагнера, в первые секунды составляет около 6,5 % от уровня мощности до остановки, через час — примерно 1,4 %, через год — 0,023 %

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


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

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


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

Конкретно на Саяно-Шушенской с аварийным электроснабжением все было хорошо — ведь ЛЭП могут работать в обе стороны, такова их природа.


Автоматика не сработала просто потому что ее залило водой.

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

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

Почти наверняка это есть. На наших АЭС есть аварийное питание «извне», здесь, на ГЭС тоже должно быть. Скорее, отключилось что-то в промежутке из-за воды.
На АЭС тоже случаются факапы, коллега АСУшник с Кольской рассказывал, что в начале двухтысячных они из-за каскадного отключения потеряли всё питание для собственных нужд и реактор сутки расхолаживался внутренней циркуляцией воды, выдержал, проверили на практике надёжность пассивной защиты. После этого отключили от энергосистемы пару местных мелких ГЭС и подключили напрямую к АЭС.
ещё одной системной ошибкой было использование идентичных парных модулей — которые в одинаковых условиях и накрываются одинаково, что и произошло. с тех пор дублирующие системы. напр. в авиации — принципиально различны
Можно тут по-подробнее? Разве в том же Boeing 737 навигационные системы и автопилот (1 и 2) по-разному работают?
Да, по-разному — от входных сигналов от датчиков и вплоть до исполнительных на мажорирующий элемент — полностью разные системы с разными хардом, логикой работы и софтом — всё разных производителей.

Навскидку нашлась примерно такая цитата:
«The Airbus and Boeing FBW computers design considerations for generic errors… The ELAC is produced by Thomson-CSF using Motorola 68010 processor, and the SEC is produced by SFENA/Aerospatiale using Intel 80186 processor»… Пробегало, что софт под них пишут тоже разные команды и категорически запрещён не только переход программистов из одной в другую, но даже неформальное общение (что бы не словить багу одинакового неправильного понимания какого-нибудь общего принципа)
Хм, в принципе логично. Спасибо за ликбез.
Чтобы штурмовать небеса, нужно хорошо знать язык Ада.


Спасибо за статью, хорошее настроение теперь обеспечено на весь оставшийся день.
Отличная исчерпывающая статья о проблеме в крупном проекте. Зря намекает Денис Решихин на ошибки в системном проектировании дизайна проекта. Конечно, никаких ошибок в дизайне изначально не было. Таких «детских просчетов» наши разработчики не допускают с печального старта в 1974 году, да и «у них» то-же. Всему виной дополнительным требования по загрузке компьютера на уровне 80% по мощности (хотя 100% загрузка бортового компьютера РН Ариан, в принципе тоже норма), из-за которых пришлось вводить ограничения на проверку параметров в коде. Плюс, грубая ошибка в использовании принципа «повторноиспользуемости кода», при отсутствии тестирования интеграции в условиях новых входных данных.
Анализ кода в этом случае ничего не даст. Ребята просто попытались «сэкономить деньги» на этапе тестирования, а не вышло.
Загрузка бортового компьютера, работающего в реальном времени на 100% — это очень плохая штука. Даже 80% — это очень много. Например у нас, в контроллерах, которые контролируют сотни мегаватт мощности, загрузка ядра процессора, имполняющего код в реальном времени не превышает 60%, а клиенты требуют вообще, чтобы было менее 50%.
Просто Вы не в курсе, что кроме Intel существуют другие аппаратные архитектуры, где загрузка почти 100% — это НОРМА, не приводящая к проблемам в эксплуатации. А Ваши клиенты правильно требуют снижения нагрузки на Intel-архитектуру, которая в большинстве случаев не должна превышать 35%, если речь идет о какой-то надежности.

Э… а с Intel-архитектурой-то что не так?!

А Ваши клиенты правильно требуют снижения нагрузки на Intel-архитектуру, которая в большинстве случаев не должна превышать 35%, если речь идет о какой-то надежности.

Хе-хе, а о какой именно из Intel архитектур идет речь?
Поймали на неточности определений. Речь идет о стандартной архитектуре компьютера х86 (IBM PC). Архитектура х86 весьма проста и незамысловата, где главная проблема и тормоз — общая шина и соответственно неудовлетворительный IO, которым, грубо говоря, управляет — CPU.
Вы, похоже не понимаете, о чем я.
В системах реального времени одна и та же задача запускается циклически, например каждые 100мкс. Естественно, она должна выполниться за это время или быстрее. Загрузка процессора в этом случае определяется отношением времени фактического выполнения задачи к общему времени цикла. Т.е. если задача выполнится за 45µs, имеем 45% загрузки процессора. Оставшееся время обычно благодаря преемптивности отдается задачам низшего приоритета, или под non-realtime задачам.

Теперь предположим, что у вас есть задача, состоящая из куска кода АДА в статье. Рассмотрим ее с точки зрения зависимости времени выполнения этого куска кода от исходных данных.
Вы легко можете заметить, что если переменная L_M_BV_32 будет больше 32767, то в операции if присвоение произойдет после первого сравнения и программа пойдет дальше. Следующее сравнение elseif с -32676, а также операция после Else не будет выполнены вообще. Следовательно в этом случае общее время выполнения данного куска кода будет минимально.
Отлично. Мы посчитали загрузку проца, выполняя данный код с такими данными, а затем выбрали процессор, чтобы загрузка была почти 100%. И что мы имеем? В один прекрасный момент у нас другие исходные данные и в if не выполняется первое условие, не выполняется второе и мы заканчиваем в else, выполнив одно лишнее сравнение, да еще и функцию приведения вдобавок. В результате время, затраченное на выполнение этого куска кода будет в почти в два раза выше, чем мы рассчитывали. При 100%-ной оригинальной загрузке процессора, это приведет к Task Overrun — очень плохому эффекту и прощай реалтайм.

Это я к тому, что отследить и поймать самое длительное время выполнения задачи, даже прогнав ее со всеми возможными вариантами входных данных, не всегда представляется возможным, если у вас сотни тысяч строк кода и время выполнения еще зависит и от внутреннего состояния. Поэтому 100% загрузка процессора в real-time — это fail.
Мне кажется, что это Вы неправильно поняли меня. Когда я говорю о загрузке процессора, я конечно имею ввиду загрузку компьютера, где кроме CPU есть оборудование которое влияет на общую загрузку компьютера, Можно подобрать некоторое кол-во задач, которое может привести к серьезной загрузки именно CPU — но это большая редкость, особенно для х86. При разнородных задачах загрузка х86 свыше 35% — это беда, дело не в CPU, дело в арбитраже шины, в IO, контроллерах и в более медленной памяти, наконец. А с учетом того, что именно CPU обрабатывает «медленные» запросы на IO, приводит к тому, что х86 обычно не используется в критических системах в ракетной, авиационной технике, на электростанциях, заводах по обогащению урана и т.д., во всяком случае у «них».
А «100%» не может быть бедой в архитектурах «без общей шины», (хотя в реальных системах уровень держат на уровне 80%), тк задачи в РВ имеют сложную систему приоритетов и безопасности, (не хочу вдаваться глубоко в суть архитектуры) и конечно «основная задача» выполняется с высоким уровнем и если ей будет не хватать ресурсов — то замедлится исполнение задач с низкими приоритетами (обычно, такая ситуация не возникает!)
Мда, далеко вы от реалтайма ушли.
Во первых смею заметить, что во встраиваемых системах задачи известны заранее. Также известны и характеристики железа — например частота выбоки АЦП или битность данных. Поэтому такой параметр, как загрузка периферии теряет смысл — конечно она загружена на 100%. Если какая нибудь шина I2C может работать на 1МГц, она будет работать на 1МГц. А если АЦП может выдавать данные на 200MSps, зачем сне его тактировать на 100MSPs? Если я так буду делать, значит выбор АЦП не правильный.
Странно, Вы вроде бы с турбинами работаете с критическими приложениями, а так поверхностно подходите к пониманию загрузки компьютера. Может быть у Вас на каждый АЦП отдельно РС-шка стоит (гротеск!), тогда Вам меня не понять. Я говорю о бортовых системах, которые должны надежно исполнять несколько критических приложений параллельно, при этом гарантированно исполнять свою задачу. Чтобы исключить дальнейшие споры, я опишу несколько преимуществ бортовых вычислителей:
* CPU вообще не занимается операциями ввода-вывода (поэтому и может работать при 100% загрузке), соответственно не нормируется и спокойно расширяется линейка устройств ввода-вывода, которая может быть добавлена в систему без upgrade центральных процессоров (Телеметрия, Логи, АЦП, спецустройства, ...) Таким образом гарантируется высочайшая пропускная способность бортовой вычислительной системы.
* Отсутствуют накладные расходы ОС на переключение контекста процессора, более того, если кол-во задач не превышает 32, то переключение контекста отсутствует полностью.
* Реализация части функций ОС — аппаратурой
Есть масса других особенностей, выгодно отличающихся от архитектуры х86 в части надежности и безопасности. Подобные вычислители работают со времен Space Shuttle и Бурана и отлично работают.
Да, и называются они ПЛИС. Только к загрузке процессора это имеет мало отношения.
Требование загрузки в 80% — это требование резерва мощности CPU на случай, если какой-то модуль потребует больше вычислений. Дело не в архитектуре, а в том, что заранее предусматривается, что может быть проблема, из-за которой некий модуль жрать CPU. А доказать, что таких ситуаций быть не может — сложнее, чем оставить резерв.

Всему виной дополнительным требования по загрузке компьютера на уровне 80% по мощности (хотя 100% загрузка бортового компьютера РН Ариан, в принципе тоже норма), из-за которых пришлось вводить ограничения на проверку параметров в коде. Плюс, грубая ошибка в использовании принципа «повторноиспользуемости кода», при отсутствии тестирования интеграции в условиях новых входных данных.


Да, согласен

P.S.

Оставлю здесь фрагмент с source code

According to a presentation by Jean-Jacques Levy (who was part of the
team who searched for the source of the problem), the actual source code
in Ada that caused the problem was as follows.
-- Vertical velocity bias as measured by sensor

L_M_BV_32 := TBD.T_ENTIER_32S ((1.0/C_M_LSB_BV) * G_M_INFO_DERIVE(T_ALG.E_BV));

-- Check, if measured vertical velocity bias ban be 
-- converted to a 16 bit int. If so, then convert

if L_M_BV_32 > 32767 then
    P_M_DERIVE(T_ALG.E_BV) := 16#7FFF#;
elsif L_M_BV_32 < -32768 then
    P_M_DERIVE(T_ALG.E_BV) := 16#8000#;
else
    P_M_DERIVE(T_ALG.E_BV) := UC_16S_EN_16NS(TDB.T_ENTIER_16S(L_M_BV_32));
end if;

-- Horizontal velocity bias as measured by sensor -- is converted to a 16 bit int without checking P_M_DERIVE

P_M_DERIVE(T_ALG.E_BH) := UC_16S_EN_16NS (TDB.T_ENTIER_16S ((1.0/C_M_LSB_BH) * G_M_INFO_DERIVE(T_ALG.E_BH)));

The last line (shown here as two lines of text) caused the overflow,
where the conversion from 64 bits to 16 bits unsigned is not protected.
The code before is protected by testing before the assignment if the
number is too big.

The correct code would have been:
L_M_BV_32 := TBD.T_ENTIER_32S ((1.0/C_M_LSB_BV) * G_M_INFO_DERIVE(T_ALG.E_BV));

if L_M_BV_32 > 32767 then
    P_M_DERIVE(T_ALG.E_BV) := 16#7FFF#;
elsif L_M_BV_32 < -32768 then
    P_M_DERIVE(T_ALG.E_BV) := 16#8000#;
else
    P_M_DERIVE(T_ALG.E_BV) := UC_16S_EN_16NS(TDB.T_ENTIER_16S(L_M_BV_32));
end if;

L_M_BH_32 := TBD.T_ENTIER_32S ((1.0/C_M_LSB_BH) * G_M_INFO_DERIVE(T_ALG.E_BH));

if L_M_BH_32 > 32767 then
    P_M_DERIVE(T_ALG.E_BH) := 16#7FFF#;
elsif L_M_BH_32 < -32768 then
    P_M_DERIVE(T_ALG.E_BH) := 16#8000#;
else
    P_M_DERIVE(T_ALG.E_BH) := UC_16S_EN_16NS(TDB.T_ENTIER_16S(L_M_BH_32));
end if;


in other words, the same overflow check should have been present for the horizontal part of the calculation (E_BH) as was already present for the vertical part of the calculation (E_BV).

See diff with correct code:

--- LIRE_DERIVE.ads 000	Tue Jun 04 12:00:00 1996
+++ LIRE_DERIVE.ads	Fri Jan 29 13:50:00 2010
@@ -3,10 +3,17 @@
 if L_M_BV_32 > 32767 then
     P_M_DERIVE(T_ALG.E_BV) := 16#7FFF#;
 elsif L_M_BV_32 < -32768 then
     P_M_DERIVE(T_ALG.E_BV) := 16#8000#;
 else
     P_M_DERIVE(T_ALG.E_BV) := UC_16S_EN_16NS(TDB.T_ENTIER_16S(L_M_BV_32));
 end if;
 
-P_M_DERIVE(T_ALG.E_BH) := 
-  UC_16S_EN_16NS (TDB.T_ENTIER_16S ((1.0/C_M_LSB_BH) * G_M_INFO_DERIVE(T_ALG.E_BH)));
+L_M_BH_32 := TBD.T_ENTIER_32S ((1.0/C_M_LSB_BH) * G_M_INFO_DERIVE(T_ALG.E_BH));
+
+if L_M_BH_32 > 32767 then
+    P_M_DERIVE(T_ALG.E_BH) := 16#7FFF#;
+elsif L_M_BH_32 < -32768 then
+    P_M_DERIVE(T_ALG.E_BH) := 16#8000#;
+else
+    P_M_DERIVE(T_ALG.E_BH) := UC_16S_EN_16NS(TDB.T_ENTIER_16S(L_M_BH_32));
+end if;

Интересна форма бортовых компьютеров, чистая функциональность без всяких графических интерфейсов, лампочек, кнопочек. Круглые разъемы напоминают чем-то советскую технику. И применены разъемы DB-9 (как в COM портах) без всяких заморочек, как простые и надежные. Правда позолоченные, не бытовой вариант.
Советская / не советская тут не причем. Есть определенные требования к разъемным соединениям по условиям работы (в данном случае наверняка виброустойчивость, герметичность и т.д.) Спроектированные в соответствии с заданными требованиями разъем будет выглядеть примерно одинакова в не зависимости от страны и её технологических традиций.

Похожие круглые разъемы используются на современных российских электровозах, в частности сам подключал во время испытаний чем-то похожим БВД-У на 2ЭС4К
Сам изначальный подход неправильный. Даже если траектория ракеты Ариан 4 такова, что углы не могут принимать некорректных значений, то всегда может отказать датчик углов или связь с ним, и получиться белиберда. Если уж хотелось сэкономить процессорное время, то надо было просто блокировать исключительную ситуацию по переполнению, благо, язык Ада это позволяет.
UFO just landed and posted this here
Я когда писал для платежной систем одной проксю для переноса платежей в другую систему, тоже шибко боялся ошибиться :) В день налички мешок собирался в каждой точке и легко можно было пролететь отдав клиенту миллион вместо тысячи. Причем у наших конкурентов ошибка возникла и к терминалам оплаты их фирмы выстроились очереди из «прочухавших» клиентов. Как потом программиста пытали, могу только догадываться. Причем заказчикам даже в таком деле все равно надо «что бы все было готово ВНЕЗАПНО!»… идиоты не догадывались, что одна ошибочка и они потеряют миллионы. Потому, я немного подзаработав балгополучно свалил.
а что за платёжная система?
Так я и сказал :) При мне там косяков не было, после меня не знаю. Это было еще в начале двухтысячных, когда все только начиналось. Сейчас там наверное штат в сто человек и тестирование по полгода :) Что до конкурентов, то конкуренты были… тоже не скажу кто, но их сегодня все знают.
Взрыв произошёл ведь «умышленный», защитный? Т.е. автоматика уничтожила ракету?
Основной подрядчик — европейская компания Airbus Defence and Space («Эрбас дифенз энд спейс»; подразделение Airbus Group, «Эрбас груп», Париж).

Airbus Group до недавнего времени называлась EADS. И в описываемые времена ни той ни другой не существовало.
Объясните мне глупому одну простую штуку.
Что мешало прогнать это самое моделирование работы системы с заранее известными параметрами выхода на орбиту ДО того, как запускать ракету?
влом было на стейджинге обкатать, наверное.
Очень верный вопрос, я тоже в недоумении: ведь технари заранее знали приблизительные параметры полёта, а значит они были бы добавлены в «эмулятор» внешних данных для компьютера ракеты, а он бы уже на тестах вышел в exception.
Тем более параметры бокового движения платформы были превышены в 5!!! раз, а не на какую-то там погрешность.

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

Такой подход ой как не раз спасал.
Думаю, что параметры конкретно этого пуска знали довольно точно. :)
Я понимаю, что написать симулятор данных с датчиков не самая простая задача. Я понимаю, что в 1996 году возможности компьютеров были существенно скромнее. Но блин, не прогнать симуляцию для первого (!) пуска ракеты стоимостью 100500 мильёнов (с) — это просто за гранью в моём скромном понимании.
P.S. Тоже активно использую unit test-ы.
Справедливости ради цена не 100500, а минимальная, чуть выше стоимости ракеты, можно считать тестовым запуском с недорогим, сравнительно, спутником.

Дорогой провал вот, цена ошибки почти 7 миллиардов, в 20(!) раз больше, может спутник еще доберется (но не факт): из последних сил на орбиту
Ну всё же вряд ли ракета была настолько бесплатна по сравнению со стоимостью какого-то количества человеко-месяцев программистов и какого-то количества машино-дней подходящей вычислительной системы.
Впрочем, я системы такой сложности не проектировал и могу недооценивать сложность её тестирования.
При первом запуске «Энергии» ситуация была очень похожа, отделались тем, что накрылась не вся ракета, а только спутник (100-тонный аппарат, хоть и спрятанный по псевдоним «габаритно-массовый макет». Один из основателей «тихоокеанской группировки спутников») — гуглить «перевертон», лучше сразу на «Буран.ру».
Это и был макет орбитального лазера.
Может у меня какой-то другой гугл, но гугление чисто «перевертон» дало много совсем не того. (нужное нашел но по запросу «перевертон спутник»)
Да, к гуглу голову.sys часто надо применять, есть такое дело.
http://www.google.ru/search?q=%D0%BF%D0%B5%D1%80%D0%B5%D0%B2%D0%B5%D1%80%D1%82%D0%BE%D0%BD+site%3Aburan.ru
Попробую, например.
Вы хотите получить прогнать _все_ возможные варианты событий при воздействии _всех_ случайных факторов (как внутренних, так и внешних) в любом мыслимом и немыслимом диапазоне — и получить на выходе 100%-ную вероятность успеха?
Предлагаю Вам оценить вероятность прихода завтра на работу и возвращения домой живым и невредимым с точностью 5%. С учетом всех возможных и невозможных помех (начиная от бокового ветра, заканчивая внезапной сменой правительства).
Потом добавьте туда то, что Вы передвигаетесь на Формула-1 в Бангладеше на максимальной (для вашего автомобиля) скорости.

Что там Ваше численное моделирование показало, ну-ка, ну-ка?..
вероятность прихода завтра на работу и возвращения домой живым и невредимым с точностью 5%


Вероятность смерти 0.1% в год, для среднего возраста. В год для оценки риска 5% вероятность 1:50, в день 1:18250.

передвигаетесь на Формула-1 в Бангладеше на максимальной (для вашего автомобиля) скорости


1:1? Не надо нарушать ПДД, это опасно.
В цифровой технике проще: ниже нулей и единиц опускаться смысла нет. А 0 и 1 это и есть все мыслимые и не мыслимые комбинации, которые можно подать на вход функции, остаётся варьировать их длиной и последовательностью.
Разве что не забывать проверять тип данных: int, bool, string, char, vector, real, double и т.д., дабы избежать сюрпризов с преобразованием. Хотя в начале функции можно любой тип приводить к нужному, далее смотреть валидность этих данных, а затем с ними работать.

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

< Что там Ваше численное моделирование показало, ну-ка, ну-ка?..
Думаю такая компания как Гугл(или IBM со своим Watson) уже давно «сканируют» всю историю человечества на предмет все возможных вариантов продолжения ситуации при схожих условиях.
Когда-то думали, что компьютеры не смогут «нормально» играть шахматы, затем «пал» Го и т.д.
— Siri, какова вероятность, что я вечером вернусь домой целым?
— Анализирую:
> статистику преступлений на пути Вашего маршрута дом-работа
> статистику аварийности на данном участке дороги
> техсостояние автомобиля
> техсостояние автомобилей в вашем городе, чьи данные доступны
> Вашу медкарту
> медкарты жителей города
> погодные условия
> количество метеоритов и комет в околоземном пространстве
> политическую ситуацию в стране и мире
> техсостояние самолётов, что будут в небе над вашим маршрутом и офисом
> короч, еще 100500 млярдов данных
и мой ответ…
42

Кстати в каком-то городе в США уже активно и успешно тестируют систему предсказаний мест преступлений!
И это работает, как Вам такой анализ?
В цифровой технике проще: ниже нулей и единиц опускаться смысла нет. А 0 и 1 это и есть все мыслимые и не мыслимые комбинации

Да ну? Все оказывается так просто… А мы то дурни мучаемся!

Кто-то недавно задвигал про то, что за счёт конечности памяти можно рассматривать программу + память как конечный автомат, посчитать все возможные исходы и просто решить задачу останова (на конечной памяти). Осталось представить пространство состояний и возможных переходов xD

Судя по минусам моего комментария выше — вариант просчитать все возможные комбинации это в принципе не посильная задача для вычислительных систем, вот минусующие и мучаются.
Хоть бы еще кто, кроме sebres, озвучил, что с моим мнением не так.
Вы забываете, что ваш анализ не включает в себя состояние системы, которую вы анализируете. Т.е. одной последовательности единиц и нулей на входе недостаточно — один раз вы подали 1,3,8, а в другой раз 8,1,3 и в результате ваша система будет иметь совершенно разные состояния, и подача следующего воздействия будет иметь совершенно разный результат. Даже время воздействия имеет смысл.
Поэтому прогнать все варианты физически невозможно даже для Ариан 5( не забываем, что дело было в 1996 году).
Спасибо большое за разъяснение, не сарказм.
Но я по прежнему с Вами не соглашусь, когда на вход системы вместе с валидными данными сыпется мусор, в конечном счете через систему пройдут все возможные вариации событий.
Да их число огромно, да это займёт ооочень много времени если бортПК медленный, но учитывая стоимость программы, оно того стоит.
Да и потом, сколько таких случаев после 96 года было?
— марсоход(не помню какой, ссылки не нашёл), женщина-программист, перед «паковкой» этого марсохода в ракету забыла затереть флэш память данных нулями, произошёл сбой программы уже на марсе, кое-как чудом оживили.
— здесь была статья про спутник, перед отправкой которого забыли отключить «писать отладку на флэш», в итоге когда место закончилось спутник затих.
И при нынешнем подходе такие истории еще впереди, а жаль.
[Dan Simmons mode]
Не иначе, как происки ИскИнов. Теперь будет принято однозначное решение, дабы исключить «человеческий фактор».
[/Dan Simmons mode].

P.S.
Чтобы штурмовать небеса, нужно хорошо знать язык Ада.

Как ни крути. Спасибо за отличную статью, и за шикарную цитату, конечно!
Я-то подумал, что софт РН прогнали через PVS, и нашли еще больше багов, чем ставшие причиной подрыва ракеты. Нет, увы, надежда не сбылась :)

А от PVS не ожидал обзоров ради обзора. Пост отличный, спору нет, но и ситуация не раз описывалась, и случай довольно старый.
Интересно, а анализаторы Ада существуют?
Ракета, спутники… все это железо. Ошибка в Therac 25 куда опаснее и интереснее.
Sign up to leave a comment.