Подтвердить что ты не робот

C (или любые) компиляторы детерминированной производительности

Во время работы над недавним проектом меня посетил представитель QA клиента, который задал мне вопрос, который я раньше не рассматривал:

Как вы знаете, что используемый вами компилятор генерирует машинный код, который точно соответствует функциональности кода c и что компилятор полностью детерминирован?

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

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

4b9b3361

Ответ 1

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

Другим подходом является, в основном, НЕ доверять выходу компилятора вообще. Любой компилятор и даже зависящий от языка (приложение G стандарта C-90, любой?) Недостатки должны быть охвачены строгим набором статического анализа, тестирования единиц и охвата в дополнение к более позднему функциональному тестированию.

Стандарт, подобный MISRA-C, может помочь ограничить ввод компилятором "безопасным" подмножеством языка C. Другой подход заключается в том, чтобы ограничить ввод компилятором подмножеством языка и проверить, какой результат для всего подмножества. Если наше приложение построено только из компонентов из подмножества, предполагается, что будет известно, какой будет выход компилятора. Обычно идет "квалификация компилятора".

Цель всего этого - ответить на вопрос представителя QA: "Мы не просто полагаемся на детерминизм компилятора, но так мы это доказываем...".

Ответ 2

Вы можете применить этот аргумент на любом уровне: доверяете ли вы сторонним библиотекам? вы доверяете ОС? доверяете ли вы процессору?

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

Аналогичные вопросы были затронуты в отношении алгоритмов шифрования - как мы узнаем, что в DES нет backdoor в NSA для отслеживания?

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

Ответ 3

Вы знаете, тестируя. Когда вы тестируете, вы тестируете свой код и компилятор.

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

Ответ 4

Доступны версии для проверки компилятора.
Тот, который я помню, "Многолетнее" .

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

Ответ 5

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

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

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

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

Ответ 6

Как вы знаете, что используемый вами компилятор генерирует машинный код, который точно соответствует функциональности кода c и что компилятор полностью детерминирован?

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

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

На самом деле это не так нечестно, как я это сделал, в общем, FAA больше заботится о том, чтобы вы были добросовестными и уверенными в том, что пытаетесь сделать хорошую работу, чем о том, что именно вы делаете.

Ответ 7

Некоторые интеллектуальные боеприпасы можно найти в журнале Crosstalk, журнал для инженеров-разработчиков программного обеспечения. Этот вопрос таков, что они проводят много часов бодрствования. http://www.stsc.hill.af.mil/crosstalk/2006/08/index.html (Если я смогу найти свои старые заметки из старого проекта, я вернусь здесь...)

Ответ 8

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

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

Несколько раз я обнаружил ошибки в компиляторе. Однажды возникла ошибка, при которой 16-битные переменные бы увеличивались, но не переносятся, и только если 16-битная переменная была частью структуры extern, определенной в файле заголовка.

Ответ 9

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

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

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

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

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

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

Ответ 10

... вы доверяете своему компилятору неявно

Вы перестанете делать это в первый раз, когда столкнетесь с ошибкой компилятора.; -)

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

Ответ 11

Ну.. вы не можете просто сказать, что доверяете свой вывод компилятора, особенно если вы работаете со встроенным кодом. Нетрудно найти расхождения между кодом, сгенерированным при компиляции одного и того же кода с разными компиляторами. Это так, потому что сам стандарт С слишком свободен. Многие детали могут быть реализованы по-разному разными компиляторами без нарушения стандарта. Как мы справляемся с этим? Мы по возможности избегаем зависимых от компилятора конструкций. Мы можем справиться с этим, выбрав более безопасное подмножество C, например Misra-C, как ранее упоминалось пользователем cschol. Мне редко приходится проверять код, сгенерированный компилятором, но это также случалось со мной иногда. Но, в конечном счете, вы полагаетесь на свои тесты, чтобы убедиться, что код ведет себя так, как предполагалось.

Есть ли лучший вариант? Некоторые люди утверждают, что есть. Другой вариант - написать свой код в SPARK/Ada. Я никогда не писал код в SPARK, но я понимаю, что вам все равно придется связать его с подпрограммами, написанными на C, которые будут обрабатывать вещи "голого металла". Красота SPARK/Ada заключается в том, что вы абсолютно уверены, что код, созданный любым компилятором, всегда будет таким же. Нет никакой двусмысленности. Кроме того, язык позволяет вам комментировать код с пояснениями о том, как должен работать код. Набор инструментов SPARK будет использовать эти аннотации, чтобы официально доказать, что написанный код действительно делает то, что описаны аннотации. Поэтому мне сказали, что для критических систем SPARK/Ada - довольно хорошая ставка. Я никогда не пробовал это сам, хотя.

Ответ 12

Попробуйте модульное тестирование.

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

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

Ответ 13

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

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

Все остальное начинает открывать банку червей. Вы должны остановиться где-нибудь, как говорит Роб.

Ответ 14

Иногда вы получаете поведенческие изменения при запросе агрессивных уровней оптимизации.

И числа оптимизации и чисел с плавающей запятой? Забудьте об этом!

Ответ 15

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

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

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

Ответ 16

Вы получите тот, который написал Дейкстра.

Ответ 17

Выберите формально проверенный компилятор, например компилятор Compcert C.

Ответ 18

  • Изменение уровня оптимизации компилятора изменит результат.
  • Незначительные изменения в функции могут сделать компилятор встроенным или больше не встроить функцию.
  • Изменения в компиляторе (например, версии gcc) могут изменить выходные данные
  • Некоторые функции библиотеки могут быть инстрицированными (т.е. испускать оптимизированную сборку), в то время как другие не являются.

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

Ответ 19

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

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

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

Ответ 20

Я думаю, что можно как-то свести эту проблему к Проблема с остановкой.

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

Если вы используете другой, "безопасный" компилятор, я не уверен. Я уверен, что писать компилятор с нуля, возможно, будет проще.

Ответ 21

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

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

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

Ответ 22

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