Comments 118
К тому же никто и не собирается переписывать все что есть, речь про написание нового кода.
Ответ на вопрос «зачем?» заключается в наличии гарантий безопасного управления памятью без оверхеда на это в рантайме. Именно это бич Си, именно это могло бы пригодиться в NASA для сверхнадёжных программ.
Только не надо говорить, что это не проблема, это уже стоило человечеству очень многие миллионы долларов в ретроспективе.
Но, естественно, нет смысла в NASA переключать сейчас разработку на RUST 1.0.сколько-то.alpha, надо дождаться стабильной стандартизированной проверенной версии, полностью на 100% отлаженного и доверенного компилятора и т.д.
Рассматривать в перспективе есть смысл, чисто из-за этой фишки с памятью.
для RUST наверняка нужен процессор с MMU (memory managment unit — блок переназначения виртуальной памяти в физическую).
А это и падение быстродействия, и требование наличия ОС, и в разы больше транзисторов и триггеров.
А всё это даёт дополнительные точки отказа, особенно в среде с повышенной радиацией, а по «праздникам» с зашкаливающей радиацией. Что есть не самая лучшая идея особенно ради просто моды.
Ладно, чёрт с ней с физикой и сложностью.
Мне вот интересно другое: есть ли методика безопасного кодинга, проверки и поиска ошибок для RUST выстраданная десятилетиями и миллиардами долларов убытков? Надёжные инструменты которые не дают незначительные ошибки раз в 100000 строк кода? Проверенные годами библиотеки? Надеюсь за фанатов что есть.
для RUST наверняка нужен процессор с MMU (memory managment unit — блок переназначения виртуальной памяти в физическую).Нет, Rust'у нафиг не нужен MMU. И вообще он один из редких совеременных языков, способных на голом «железе» сидеть, без операционки, на микроконтроллере с ограниченной памятью.
Мне вот интересно другое: есть ли методика безопасного кодинга, проверки и поиска ошибок для RUST выстраданная десятилетиями и миллиардами долларов убытков?Какие могут быть «выстраданные десятитителиями методики», если языку чуть больше года? Позаимствованные из других языков — да, есть, там много идей, «проверенных годами» идей, которые теоретически должны обеспечивать «безопасный кодинг», но как оно там на практике больших проектов в миллионы строк работать будет — ещё рано говорить.
Молодой Rust пока — это да, но задатки хорошие. Переводить на него всякие сильно критичные системы — я бы пока не стал. А вот какой-нибудь мелкий проект — уже вполне можно изображать…
Си не универсальный
Си как раз универсальный. На нем можно написать что угодно. И практически как угодно.
40 лет назад — это 76-й год. В то время в C был принят такой способ определения параметров у функции:
int foo(a, p)
int a;
char *p;
{
return 0;
}
Более-менее современный C — это ANSI C 89-го года или ISO C99.
Любой современный компилятор на такую архаичную запись выдаст предупреждение.
Я согласен с тем, что Rust хорошо сочетается с заявленными целями писать максимально безопасный код. Но если запретить динамическое выделение памяти, то его преимущества перед C радикально уменьшаются.
Don't get me wrong. Я люблю Rust и надеюсь, что он получит большее распространение в обозримом будущем.
Как пример использования. Есть функция — запаковать в пакет прикладного уровня и отправить. И у неё аргумент — функция отправки транспортного уровня. Транспортных подсистем — 3-4 штуки. Соответственно делаются обертки к функции запаковки — запаковать и отправить таким-то транспортом (или транспортом, указанным в конфиге).
В итоге получается достаточно безопасная конструкция.
Преимущество — память на прикладной конверт выделяется той функцией, которая знает, сколько памяти надо.
Все это можно сделать через свитч, но оно менее расширяемо получится.
*29 Do not use non-constant function pointers.
30 Do not cast function pointers into other types.
В случае же, когда все переходы определены в статике, бортовая вычислительная система представляет собой конечный автомат с памятью, который всегда можно перезапустить очисткой (приведением) набора входных данных к валидному состоянию.
Все вышесказанное, конечно, имеет смысл либо для гарвардских архитектур, либо для систем с защитой памяти (не обязательно имеющих виртуальную!)
Динамическая память — туда же. При отсутствии механизма виртуальной памяти невозможно гарантировать 100% корректную работу системы в течение бесконечного времени при динамическом выделении/освобождении памяти даже при любом априори предустановленном суммарном лимите для каждого процесса из-за фрагментации. При наличии механизма виртуальной памяти такое становится возможным — но взамен мы получаем лишь статистическую верхнюю границу времени отклика на выделение блока памяти
У Европейского космического агенства была крутая новая ракета Cluster. Там дажу было горячее резервирование системы управления ракетой — но и оно не спасло от необработанного exception. Обе ноды синхронно упали :)
Эта неудача входит в список самых дорогих ошибок программистов
Вот где реально интересно было бы посмотреть на результаты прогона PVS-Studio :)
Кстати да. Призываю в тред Andrey2008
В среднем должно быть не менее двух ассершнов на функцию.
The return value of non-void functions must be checked by each calling function
Возвращаемое значение не-void фунций должно проверяться вызывающей функцией.
Примечание: идея такая, что функция не должна доверять ничему вообще, кроме себя самой, ни переданным аргументам, ни значениям полученным из других функций.
А я думаю — как assert(true) может помочь обойти правило не более двух ассертов.
Так намного больше смысла.
Великолепные правила для неспешной разработки надёжных систем. Ужасные правила для быстрой разработки ненадёжных систем.
У всех циклов должен быть предел. Проверяющая программа должна иметь возможность легко доказать, что определенное количество итераций не может быть превышено. Если предел невозможно доказать статически, то правило считается нарушенным.
Хотелось бы узнать больше подробностей, ибо известно, что в общем случае проблема останова не решаема.
Какой-нибудь BPF в проблему останова ни разу не упирается, почему NASA должна?
Странная логика. Я не говорил, что "NASA должна".
В документе JPL есть много правил, но пользователь Реддита сделал выжимку десяти главных принципов.
то есть скорее всего есть какое-то формальное доказательство, что следуя всех их правилам, можно гарантировать, что программа завершиться за конечное число шагов. Я лишь хотел подчеркнуть, что вне контекста правило №2 непонятно совсем. Более того, непонятно, как его выполнять.
На практике это означает, что сложные алгоритмы должны быть ограничены не только достижением результата, но и заданным количеством итераций до неуспеха.
Вот пример
http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/20030017985.pdf
Да и вот тут много чего интересного есть
http://lars-lab.jpl.nasa.gov/
Что-то я сомневаюсь, что дело в 10 правилах.
Дело скорее:
В детальном прописывании спецификаций и их низменности на протяжении всего времени разработки
В статическом анализе кода
В обязательном code review
В огромных затратах на тестирование
В таких условиях неважно на каком языке ты пишешь и какого стиля придерживается.
Очевидно, что правила про отсутствие динамической памяти, рекурсии, ограниченность циклов и отсутствие указателей на функции появились чтобы упростить работу статическому анализатору
Анализатору и компилятору пофиг, он машина. Запятые, скобки на месте? Годен! А вот живому человеку сложно читать и отлаживать код, в котором много условностей и контекстов. Забудешь вернуть память или выйти из рекурсии — и привет. Проще это болото обойти, потратишь лишний час разработки, но сэкономишь недели и месяцы отладки.
На моей практике наблюдалось явление: чем больше код проверяется, тем внимательнее пишут программисты. Это касается именно проверки исходников, а не тестирования.
Добавляя статические проверки и code review к процессу можно сразу получить на порядок лучшее качество.
Видимо срабатывает логика: код будут проверять — надо писать хорошо. И обратная логика тоже работает прекрасно. Если никто по факту не код не проверяет, то пишут его абы-как.
Еще раз повторю тезис.
Дело вовсе не в отказе, в большем контроле что пишут программисты.
Сколько бы ограничений вы не вводили — это не поможет не писать говнокод, если программист захочет.
А если заранее спланировать что напишет программист, проверить статическим анализатором, прогнать через code review минимум двух человек и потратить в два раза больше времени на тестирование, то по сути пофиг какие там ограничения вы себе навводили.
Вот, к примеру, 5-й пункт про ассерты. Они никак не влияют на функционал, это тесты. Они жрут такты при каждом вызове функции, особенно в циклах. Но это самые точные тесты, которые легко поддерживать актуальными. А еще они, в отличии от юнит-тестов, способны сохранить программу «на плаву» уже в полете, когда невозможное случилось и без отладчика точно указать на проблемное место.
или 7-й пункт, проверять все, что пришло снаружи или изнутри, будь то параметры или результаты. Например, банальная функция инкремента. Знаете, что будет с байтом 0xFF, если его увеличить на единицу? Будет ноль. А это во некоторых случаях может привести к беде. Поэтому в самом инкременте должен быть ассерт на переполнение, и на выходе нужно проверить, что результат инкремента является допустимым. Глупости? Отнюдь! Реальный пример — при формировании более светлого цвета фона для выделения важного сообщения происходило переполнение байтов RGB и получался черный текст на черном фоне. 15 лет работало нормально, а потом в системе поменяли цвет фона на чисто белый (0xFFFFFF) и получился эпический фейл. Вот каким анализатором или code review можно было такое предусмотреть?
С указателями самая больная тема. Нетипизированные указатели это граната с обезьяной. Проще сразу отказаться, чем потом страдать. Память из кучи это по сути своп — там и фрагментация свободного места, и конфликты, и утечки. Когда используется всего 5-10% от свободного объема, то это незаметно. А когда памяти впритык, то начинает всякая фигня происходить. Может всплыть через месяц, через год. Поэтому тестирование таких вещей идет неделями с 10-кратной нагрузкой на пределе возможностей железа.
Высокодуховный код безбажен по определению :)
«Our requirements are almost pseudo-code,» says William R. Pruett, who manages the software project for NASA. «They say, you must do exactly this, do it exactly this way, given this condition and this circumstance.»
The group has one customer, a smart one. And money is not the critical constraint.
Ничуть не принижая способности их разработчиков, следует отметить, что с организационной точки зрения условия им созданы очень близкие к идеальным.
в системе должно быть 0 (ноль) ошибок на 560 000 строк кода. И работать она должна несмотря ни на какие сбои и неполадки железа и софта, ошибки персонала.
Стандартное в наши дни требование практически от любого заказчика в корпоративном сегменте :)
А если серьезно, то некоторые из описанных задач, конечно, далеко не для любого студента. Поделитесь, какими способами пытаетесь поддерживать низкое количество ошибок в системе, в которой есть сторонние компоненты, включая целые базы данных, а также
некоторые драйвера устаревших приборов невозможно протестировать и отладить, потому что они сложные, к ним нет ни документации, ни тестовых приборов
? Используете похожие на NASA'вские правила при разработке? Требуете как и они от заказчика подробнейшие спецификации? Содержите ли сильнейший отдел тестировщиков? Пытаетесь вытягивать на личных профессиональных качествах старших разработчиков?
Лично я правила использую. Но не всегда им строго следую. Требовать спецификации можно, но не всегда успешно. И в них могут быть ошибки, устаревшие сведения. Только практика, испытания и анализ дают достоверный результат. Тестировщики есть, и очень дотошные. Личные качества вообще самое главное, ведь технику делают люди.
Требовать спецификации можно, но не всегда успешно. И в них могут быть ошибки, устаревшие сведения.
"В 1962 году головной по командному модулю кораблей серии «Аполлон» фирмой «North American Aviation» (позже — «North American Rockwell») при изменении технического задания на изготовление кислородных баллонов для двигательных отсеков, выданного субподрядчику фирме «Beech Aircraft», не была предусмотрена модификация термостатов, изначально рассчитанных на напряжение 28 В, под стандартное для наземного оборудования стартового комплекса напряжение в 65 В. Это несоответствие не было замечено ни специалистами обеих фирм, ни НАСА. [...] проведённые в ходе расследования эксперименты показали, что эти выключатели, рассчитаные на питание в 28 вольт постоянного тока от батарей служебного модуля, не размыкались должным образом при работе под напряжением 65 В, подаваемым со стартового комплекса в ходе выпаривания кислорода."
Когда я впервые столкнулся с этим при разработке под игровые приставки (на картриджах), то тоже был несколько скептичен. Зачем же себя так ограничивать? Но позже, при отладке совершенно непонятных рандомных глюков, постепенно пришлось отбрасывать весь синтаксический сахар, регламентировать работу с памятью и вставлять сотни ассертов. В итоге ошибка находилась, они могла быть совсем пустяковой, и не влиять на работу сразу, а вызывать сбой где-то в другом месте программы.
Я бы еще добавил, что очень важна строгая типизация и однозначно говорящие имена функций и переменных. Сколько угодно случаев, когда тупиковая ситуация переставала быть тупиковой, когда вещи называли своими именами.
#define TRUE 1
#define FALSE 0
typedef int BOOL;
// где-то в коде
BOOL a;
// повсеместно заместо
// a = TRUE;
a += 1;
Вторые — гарантированно воспроизводимы на уровне, скажем, не ниже четверки по профильному предмету при применении обучающего курса Х в течение Y лет.
Как и любая индустрия, космическая промышленность нуждается в определенном количестве специалистов, способных решать задачи определенного класса с качеством не ниже определенного. Дальше — теория вероятности — чем выше требования к качеству — тем меньшее количество людей статистически годны для решения задач — а значит, а) процесс становится более персонозависимым, и б) прогноз выхода специалистов нужного уровня — недостоверным
Это допустимо (и усиленно используется!) в гуманитарной области (поэты, художники итд) — но совершенно недопустимо в инженерии. Поэтому вводятся искусственные ограничения, повышающие надежность за счет снижения разрешенного множества выразительных средств — этими мерами процесс выводится из зоны персонозависимости. Снижение эффективности кода и/или красоты решения в данном случае не играют никакой роли (так как либо легко парируются техническими средствами, либо не являются метрикой качества/престижа разработчика вообще)
Уместна аналогия с переходом от аналогового к цифровому аудио — да, аналоговая запись единственна и неповторима — но она и немасштабируема! Сознательное же внесение искажений в идеал (квантование) позволяет сделать предсказуемой любую ее копию.
вызывающей функцией
Rule 14 (checking return values)
The return value of non-void functions shall be checked or used by each
calling function, or explicitly cast to (void) if irrelevant.
Копия статьи: web.eecs.umich.edu/~imarkov/10rules.pdf
Статья в Википедии: en.wikipedia.org/wiki/The_Power_of_10:_Rules_for_Developing_Safety-Critical_Code
Я думаю, что это все-таки не какие-то определенные правила «позволяют NASA писать миллионы строк кода с минимальными ошибками», а ответственность людей, которые там работают. Наличие правил и их теоретическая осмысленность не гарантируют того, что им будут следовать или применять так, как предполагалось. Скорее все-таки, это в NASA это общее понимание потенциальных последствий даже, казалось бы, маленьких ошибок, заставляет людей намного более ответственно относиться к тому, что они производят, чем в большинстве ПО общего потребления, где факапы не столько значимы.
10 правил, которые позволяют NASA писать миллионы строк кода с минимальными ошибками