"Illegale Hardware-Anweisung" aus sehr einfachem Code

9

Während ich eine zweifelhafte Behauptung untersuchte , schrieb ich dieses kleine Testprogrammnoway.c

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

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

Wenn ich das teste, bekomme ich:

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

Wat.

Wenn ich ohne Optimierungen kompiliere, hängt es wie erwartet. Ich habe mir die Baugruppe angesehen, und ohne Schnickschnack mainsieht die Funktion folgendermaßen aus:

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

Wo ud2ist anscheinend eine Anweisung speziell für undefiniertes Verhalten. Die oben erwähnte zweifelhafte Behauptung "Eine Funktion, die niemals zurückkehrt, ist UB" wird verstärkt. Es fällt mir immer noch schwer zu glauben. Ja wirklich!? Sie können eine Spin-Schleife nicht sicher schreiben?

Meine Fragen sind also:

  1. Ist das eine korrekte Lesart dessen, was los ist?
  2. Wenn ja, kann mich jemand auf eine offizielle Ressource verweisen, die dies überprüft?
  3. In welcher Situation soll diese Art der Optimierung stattfinden?

Relevante Infos

$ 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
quelle
3
IIRC, signierter int-Überlauf ist UB.
Wildplasser
1
^^^^ dh int n = 0===> unsigned int n = 0;oder noch besser ..while (1);
WhozCraig
1
Hmmm ... Compiler Explorer clang erhält eine Selbstziel-Sprunganweisung mit -O gcc.godbolt.org/z/NTCQYT und eine zeilenweise Übersetzung ohne diese. Scheint in vielen Versionen konsistent zu sein. Aber ich erinnere mich auch daran (obwohl ich es nicht nachschlagen werde), dass der C-Standard besagt, dass eine Nichtbeendigung ub ist, wenn sie frei von Nebenwirkungen ist . Hier erklärt Hans Boehm, dass dies bestimmte ansonsten unmögliche Compiler-Optimierungen ermöglicht: open-std.org/jtc1/sc22/wg14/www/docs/n1528.htm
Gene
1
Das undefinierte Verhalten ist ein vorzeichenbehafteter Ganzzahlüberlauf, nicht die Endlosschleife. Sie können es beheben, indem Sieunsigned int
MM
2
@Gene Ich glaube nicht, dass es das sagt. Es kann davon ausgegangen werden, dass Sideffect-freie Schleifen mit nicht konstanten Steuerungsausdrücken beendet werden ( port70.net/~nsz/c/c11/n1570.html#6.8.5p6 ), aber eine ausgelastete Schleife sollte in Ordnung sein. Der UB befindet sich im Integer-Überlauf, obwohl ich das Beispiel mit dem UD-Befehl nicht reproduzieren kann.
PSkocik

Antworten:

3

Wenn Sie das ud2 für den Code erhalten, der jetzt in Frage kommt, ist der Compiler kein konformer C-Compiler. Sie könnten einen Compiler-Fehler melden.

Beachten Sie, dass dieser Code in C ++ tatsächlich UB ist. Beim Hinzufügen von Threads (C11 bzw. C ++ 11) wurde eine Vorwärtsfortschrittsgarantie für jeden Thread eingerichtet, einschließlich des Hauptausführungsthreads eines Programms, das nicht über mehrere Threads verfügt.

In C ++ müssen schließlich alle Threads ohne Ausnahmen fortschreiten. In C ist jedoch keine Schleife erforderlich, deren steuernder Ausdruck ein konstanter Ausdruck ist. Nach meinem Verständnis hat C diese Ausnahme hinzugefügt, da es in der eingebetteten Codierung bereits üblich war, a while(1) {}zum Aufhängen des Threads zu verwenden.

Ähnliche Frage mit detaillierteren Antworten

MM
quelle
Ja, ich bekomme das ud2aus dem C-Code, aber ich danke Ihnen, dass Sie die Informationen zur C ++ - Vorwärtsfortschrittsgarantie (ein Begriff, den ich anscheinend recherchieren kann) aufgenommen haben, nach dem ich wirklich gefragt habe, den ich aber optimiert habe Ich habe die Frage vorbereitet.
Luqui
Eine bessere Formulierung dessen, was das Normungskomitee meiner Meinung nach zu sagen versuchte, ist, dass, wenn das Verschieben von allem innerhalb einer Schleife nach einer bestimmten Operation das Programmverhalten nicht merklich beeinflussen würde, das Verschieben der Ausführung der Schleife als Ganzes nach dieser Operation nicht als eine Operation betrachtet würde beobachtbare Verhaltensänderung.
Supercat