L'existence d'une telle instruction dans un programme donné signifie-t-elle que l'ensemble du programme n'est pas défini ou que le comportement ne devient indéfini qu'une fois que le flux de contrôle atteint cette instruction?
Ni. La première condition est trop forte et la seconde est trop faible.
Les accès aux objets sont parfois séquencés, mais la norme décrit le comportement du programme en dehors du temps. Danvil a déjà cité:
si une telle exécution contient une opération indéfinie, la présente Norme internationale n'impose aucune exigence sur l'implémentation exécutant ce programme avec cette entrée (pas même en ce qui concerne les opérations précédant la première opération non définie)
Cela peut être interprété:
Si l'exécution du programme produit un comportement indéfini, alors tout le programme a un comportement indéfini.
Ainsi, une instruction inaccessible avec UB ne donne pas au programme UB. Une instruction accessible qui (à cause des valeurs des entrées) n'est jamais atteinte, ne donne pas au programme UB. C'est pourquoi votre première condition est trop forte.
Maintenant, le compilateur ne peut pas en général dire ce que contient UB. Donc, pour permettre à l'optimiseur de réorganiser les instructions avec UB potentiel qui serait réordonnable si leur comportement était défini, il est nécessaire de permettre à UB de "remonter dans le temps" et de se tromper avant le point de séquence précédent (ou en C ++ 11, pour que l'UB affecte les choses qui sont séquencées avant la chose UB). Par conséquent, votre deuxième condition est trop faible.
Un exemple majeur de ceci est lorsque l'optimiseur s'appuie sur un aliasing strict. L'intérêt des règles strictes d'aliasing est de permettre au compilateur de réorganiser les opérations qui ne pourraient pas être réordonnées valablement s'il était possible que les pointeurs en question alias la même mémoire. Ainsi, si vous utilisez des pointeurs d'aliasing illégal et que UB se produit, cela peut facilement affecter une instruction "avant" l'instruction UB. En ce qui concerne la machine abstraite, l'instruction UB n'a pas encore été exécutée. En ce qui concerne le code objet réel, il a été partiellement ou entièrement exécuté. Mais la norme n'essaie pas d'entrer dans les détails sur ce que signifie pour l'optimiseur de réorganiser les instructions, ou quelles en sont les implications pour UB. Cela donne simplement à la licence d'implémentation une erreur dès qu'il le souhaite.
Vous pouvez penser à cela comme "UB a une machine à remonter le temps".
Plus précisément pour répondre à vos exemples:
- Le comportement n'est indéfini que si 3 est lu.
- Les compilateurs peuvent éliminer le code comme étant mort et le font si un bloc de base contient une opération qui ne sera certainement pas définie. Ils sont autorisés (et je suppose que oui) dans les cas qui ne sont pas un bloc de base mais où toutes les branches mènent à UB. Cet exemple n'est pas un candidat à moins
PrintToConsole(3)
d'être connu pour être sûr de revenir. Cela pourrait lever une exception ou autre.
Un exemple similaire à votre deuxième est l'option gcc -fdelete-null-pointer-checks
, qui peut prendre un code comme celui-ci (je n'ai pas vérifié cet exemple spécifique, considérez-le comme illustratif de l'idée générale):
void foo(int *p) {
if (p) *p = 3;
std::cout << *p << '\n';
}
et changez-le en:
*p = 3;
std::cout << "3\n";
Pourquoi? Parce que si p
est nul, le code a de toute façon UB, de sorte que le compilateur peut supposer qu'il n'est pas nul et optimiser en conséquence. Le noyau Linux a trébuché là-dessus ( https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2009-1897 ) essentiellement parce qu'il fonctionne dans un mode où le déréférencement d'un pointeur nul n'est pas censé be UB, cela devrait entraîner une exception matérielle définie que le noyau peut gérer. Lorsque l'optimisation est activée, gcc nécessite l'utilisation de-fno-delete-null-pointer-checks
afin de fournir cette garantie hors norme.
PS La réponse pratique à la question "Quand un comportement indéfini frappe-t-il?" est "10 minutes avant votre départ pour la journée".