"Незаконна інструкція по апаратному забезпеченню" з дуже простого коду


9

Досліджуючи сумнівну претензію , я написав цю маленьку тестову програмуnoway.c

int proveit()
{
    unsigned int n = 0;
    while (1) n++;
    return 0;
}

int main()
{
    proveit();
    return 0;
}

Тестуючи це, я отримую:

$ clang -O noway.c
$ ./a.out
zsh: illegal hardware instruction  ./a.out

Ват.

Якщо я компілюю без оптимізацій, він висить, як очікувалося. Я подивився на збірку, і без усіх дзвіночків mainфункція виглядає так:

_main:                                  ## @main
    pushq   %rbp
    movq    %rsp, %rbp
    ud2

Де ud2, мабуть, є інструкція спеціально для невизначеної поведінки. Згадана вище сумнівна претензія "Функція, яка ніколи не повертається, є UB", посилена. Мені все ще важко повірити. Дійсно !? Ви не можете безпечно написати цикл віджиму?

Тож я думаю, мої запитання:

  1. Це правильне читання того, що відбувається?
  2. Якщо так, чи може хтось вказати мені на якийсь офіційний ресурс, який це підтверджує?
  3. Яка ситуація, в якій ви хотіли б провести такий тип оптимізації?

Відповідна інформація

$ clang --version
Apple clang version 11.0.0 (clang-1100.0.20.17)
Target: x86_64-apple-darwin18.6.0
Thread model: posix
InstalledDir: /Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

3
IIRC, підписаний int overflow є UB.
wildplasser

1
^^^^ тобто int n = 0===> unsigned int n = 0;або ще краще ..while (1);
WhozCraig

1
Гммм ... Компілятор провідника компілятора отримує інструкцію про стрибок з самонаціленою ціллю з -O gcc.godbolt.org/z/NTCQYT та безлінійним перекладом без неї. Здається, послідовно в багатьох версіях. Але я також нагадую (хоча не буду це шукати), що стандарт C говорить, що не припинення є ub, якщо це не має побічних ефектів . Ось Ганс Бем , пояснюючи , що це дає змогу деяким інакше, неможливі оптимізації компілятора: open-std.org/jtc1/sc22/wg14/www/docs/n1528.htm
Gene

1
Невизначена поведінка підписується цілим переповненням, а не нескінченним циклом. Ви можете виправити це за допомогоюunsigned int
ММ

2
@Gene Я не думаю, що це говорить про це. Цифри, що не містять бічних ефектів, з виразами, що не контролюють const, можуть вважати, що вони закінчуються ( port70.net/~nsz/c/c11/n1570.html#6.8.5p6 ), але циклічне зайняття має бути добре. UB знаходиться в цілому переповненні, хоча я не можу відтворити приклад з інструкцією UD.
PSkocik

Відповіді:


3

Якщо ви отримаєте ud2 для коду, про який зараз йдеться, компілятор не є відповідним компілятором C. Ви можете повідомити про помилку компілятора.

Зауважте, що в C ++ цей код насправді буде UB. Коли були додані потоки (C11 та C ++ 11 відповідно), було встановлено гарантію прогресу вперед для будь-якого потоку, включаючи основний потік виконання програми, що не є багатопотоковою.

У C ++ всі потоки повинні з часом розвиватися, без винятку. Однак у C циклі, контрольним виразом якого є постійний вираз, не потрібно просуватися. Я розумію, що C додав цей виняток, тому що вже було звичною практикою у вбудованому кодуванні використовувати a, while(1) {}щоб повісити нитку.

Подібне запитання з більш детальними відповідями


Так, я отримую ud2від коду С, але дякую, що включив інформацію про гарантію прогресу вперед на C ++ (термін, який, здається, я зможу дослідити), про що я справді просив, але отримав, ну, оптимізований як Я готував питання.
luqui

Кращою фразою того, що, на мою думку, намагався сказати Комітет стандартів - це те, що якщо відкладання всього циклу, що минув певну операцію, не помітно вплине на поведінку програми, відклавши виконання циклу як минулого, ця операція не вважатиметься помітна зміна поведінки.
Supercat
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.