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


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

Должно ли это произойти в соответствии со спецификацией компилятора, или это ошибка в компиляторе?

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

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

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

Edit: он генерирует инструкцию ud2...

1 5

1 ответ:

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

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

Сохраняет значение null, а вызовы через нулевые указатели превращаются в _Вызов _builtin_trap () (который превращается в ловушка инструкции, как " ud2 " на x86). Они происходят все время в оптимизированном коде (так как результат других преобразований, таких как inlining и constant распространение) и мы привыкли просто удалять блоки, которые их содержали потому что они были "явно недостижимы".

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

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

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