«Instruction matérielle illégale» à partir d'un code très simple

9

En enquêtant sur une affirmation douteuse , j'ai écrit ce petit programme de testnoway.c

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

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

En testant cela, je reçois:

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

Wat.

Si je compile sans optimisations, il se bloque comme prévu. J'ai regardé l'assemblage, et sans toutes les cloches et les sifflets, la mainfonction ressemble à ceci:

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

ud2est apparemment se trouve une instruction spécifique pour un comportement non défini. La revendication douteuse susmentionnée, "Une fonction qui ne revient jamais est UB", est renforcée. J'ai quand même du mal à y croire. Vraiment!? Vous ne pouvez pas écrire une boucle de rotation en toute sécurité?

Je suppose donc que mes questions sont les suivantes:

  1. Est-ce une lecture correcte de ce qui se passe?
  2. Si oui, quelqu'un peut-il m'indiquer une ressource officielle qui le vérifie?
  3. Dans quelle situation souhaiteriez-vous que ce type d'optimisation se produise?

Informations pertinentes

$ 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
luqui
la source
3
IIRC, signé débordement int est UB.
Wildplasser
1
^^^^ ie int n = 0===> unsigned int n = 0;ou mieux encore ..while (1);
WhozCraig
1
Hmmm ... Compiler Explorer clang obtient une instruction de saut auto-cible avec -O gcc.godbolt.org/z/NTCQYT et une traduction ligne par ligne sans elle. Semble cohérent dans de nombreuses versions. Mais je me souviens aussi (bien que je ne le chercherai pas) que la norme C indique qu'une non-terminaison est ub si elle est sans effet secondaire . Voici Hans Boehm expliquant que cela permet certaines optimisations du compilateur autrement impossibles: open-std.org/jtc1/sc22/wg14/www/docs/n1528.htm
Gene
1
Le comportement indéfini est le débordement d'entier signé, pas la boucle infinie. Vous pouvez le réparer en utilisantunsigned int
MM
2
@Gene Je ne pense pas que cela dise cela. Les boucles sans effet secondaire avec des expressions de contrôle non const peuvent être supposées se terminer ( port70.net/~nsz/c/c11/n1570.html#6.8.5p6 ) mais le bouclage occupé devrait être correct . L'UB est dans le débordement d'entier, bien que je ne puisse pas reproduire l'exemple avec l'instruction UD.
PSkocik

Réponses:

3

Si vous obtenez l'ud2 pour le code qui est maintenant dans la question, alors le compilateur n'est pas un compilateur C conforme. Vous pouvez signaler un bogue du compilateur.

Notez qu'en C ++, ce code serait en fait UB. Lorsque des threads ont été ajoutés (C11 et C ++ 11 respectivement), une garantie de progression vers l'avant a été mise en place pour tout thread, y compris le thread d'exécution principal d'un programme qui n'est pas multi-thread.

En C ++, tous les threads doivent éventuellement progresser, sans exception. Cependant en C, une boucle dont l'expression de contrôle est une expression constante n'est pas requise pour progresser. Je crois comprendre que C a ajouté cette exception car il était déjà courant dans le codage intégré d'utiliser un while(1) {}pour suspendre le thread.

Question similaire avec des réponses plus détaillées

MM
la source
Oui, je reçois le ud2code C, mais merci d'avoir inclus les informations sur la garantie de progression de C ++ (terme qu'il semble que je pourrai rechercher), c'est ce que je demandais vraiment, mais j'ai été optimisé comme Je préparais la question.
luqui
Une meilleure formulation de ce que, selon moi, le Comité des normes tentait de dire est que si le report de tout dans une boucle au-delà d'une certaine opération n'affectait pas de manière observable le comportement du programme, le report de l'exécution de la boucle dans son ensemble après cette opération ne serait pas considéré comme un changement de comportement observable.
supercat