C с результатами undefined, компилятор генерирует неверный код (с -O3)

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

Предполагается, что это произойдет в соответствии со спецификацией компилятора или это ошибка в компиляторе?

Здесь (простая) программа, которую я использую:

int main() {
    char *ptr = 0;
    *(ptr) = 0;
}

Я компилирую с -O3. Это не должно генерировать неверные аппаратные инструкции, верно? С -O0 я получаю segfault при запуске кода. Это кажется намного более разумным.

Изменить: он генерирует инструкцию ud2...

Ответ 1

Инструкция ud2 является "действительной инструкцией", и она означает Undefined Инструкция и генерирует недопустимое исключение кода операции clang и, по-видимому, gcc может генерировать этот код, когда программа вызывает поведение Undefined.

От ссылки clang выше логическое обоснование объясняется следующим образом:

Хранилища до нуля и вызовы с помощью нулевых указателей превращаются в __builtin_trap() (который превращается в команду захвата, такую ​​как "ud2" на x86). Все это происходит в оптимизированном коде (как результат других преобразований, таких как inline и постоянная распространение), и мы просто удалили блоки, которые содержали их потому что они "явно недостижимы".

Хотя (с точки зрения адвоката педантичного языка) это строго true, мы быстро узнали, что люди иногда разыгрывают нулевое значение указатели и выполнение кода просто попадают в верхнюю часть следующая функция затрудняет понимание проблемы. Из угол действия, наиболее важным аспектом их раскрытия является для сквош-кода. Из-за этого, clang превращает их в runtime trap: , если один из них фактически динамически достигнут, программа немедленно останавливается и может быть отлажена. Недостаток это то, что мы слегка раздуваем код, имея эти операции и имея условия, которые контролируют их предикаты.

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

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