Определение Undefined Поведение - программирование
Подтвердить что ты не робот

Определение Undefined Поведение

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

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

Изменить: Чтобы сделать это немного точнее: я хотел бы иметь компилятор, который позволяет мне сделать утверждение для данного запуска программы на С++, которая выполнялась до завершения, что нет часть этого запуска включала поведение undefined.

4b9b3361

Ответ 1

Да и нет.

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

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

int a;
int* b;

int foo() {
  a = 5;
  b = &a;
  return 0;
}

int bar() {
  *b = a;
  return 0;
}

int main() {
  std::cout << foo() << bar() << std::endl;
}

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

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

Ответ 2

Новый стандарт C имеет интересный список в новом Приложении L с сырым заголовком "Анализируемость". В нем говорится о UB, который является так называемым критическим UB. Это включает в себя, среди прочего:

  • Объект упоминается вне его времени жизни (6.2.4).
  • Указатель используется для вызова функции, тип которой несовместим с указанным тип
  • Программа пытается изменить строковый литерал

Все это UB, которые невозможно или очень сложно захватить, поскольку они обычно не могут быть полностью протестированы во время компиляции. Это связано с тем, что действительная C (или С++) программа состоит из нескольких единиц компиляции, которые могут не знать многого другого. Например, если одна программа передает указатель на строковый литерал в функцию с параметром char* или, что еще хуже, программу, которая отбрасывает const -ness из статической переменной.

Ответ 3

Два интерпретатора C, которые обнаруживают большой класс поведения undefined для большого поднабора последовательных C, KCC и Анализ значений Frama-C. Они оба используются, чтобы убедиться, что автоматически сгенерированные, автоматически уменьшенные случайные программы C подходят для report ошибок в компиляторах C.

На веб-странице KCC:

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

Третий интерпретатор для диалекта C - это режим интерпретатора CompCert (a writeup). Это определяет все типы поведения undefined на языке ввода сертифицированного компилятора C CompCert. Язык ввода CompCert - это, по существу, C, но он определяет определенные типы поведения undefined в стандарте (подписанное арифметическое переполнение определяется, например, как результат вычисления 2-го уровня).

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

Ответ 4

Вся суть определения чего-то как "поведения undefined" заключается в том, чтобы не обнаружить эту ситуацию в компиляторе. Он определен таким образом, так что компиляторы могут быть созданы для самых разных платформ и архитектур, и поэтому для аппаратного и программного обеспечения необязательно иметь конкретные функции "просто для обнаружения поведения undefined". Представьте, что у вас есть подсистема памяти, которая не может определить, записываете ли вы в реальную память или нет, - как бы система компилятора или системы выполнения обнаружила, что вы только что сделали somepointer = rand(); *somepointer = 42;

Вы можете обнаружить НЕКОТОРЫЕ ситуации. Но чтобы требовать, чтобы ВСЕ были обнаружены, сделало бы жизнь очень трудной.

Учитывая Редактирование в исходном вопросе: я до сих пор не думаю, что это возможно для C в. Существует так много свободы делать почти что угодно (делая указатели почти на все, эти указатели могут быть преобразованы, проиндексированы, пересчитаны, и всевозможные другие вещи), и сможет вызывать всевозможные действия undefined. Существует список всех undefined поведения в C здесь - в нем перечислены 186 различных обстоятельств поведения undefined, начиная от обратной косой черты, как последний символ файла (вероятно, приведет к ошибке компилятора, но не определен как один): "Функция сравнения, вызываемая функцией bsearch или qsort, возвращает значения порядка упорядочения непоследовательно".

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

struct {
    char name[20];
    char street[20];
    int age;
    char post_code[10];
};

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