Undefined behavior (UB, nicht definiertes Verhalten) sind Handlungen im Code, deren Verhalten durch den Standard nicht definiert ist. In solchen Fällen kann der Compiler jede Entscheidung treffen: Das Programm kann auf verschiedenen Plattformen, Compilern unterschiedlich arbeiten oder sogar einen Atomkrieg auslösen (formal!). Die Verwendung von UB ist der gefährlichste Fehler in C++.
Beispiele für UB:
int* p = new int[2]; delete[] p; int x = p[1]; // UB: Zugriff auf Speicher nach der Freigabe
Um UB zu vermeiden:
Was passiert beim folgenden Code?
int a = 42; int b = a++ + ++a;Welchen Wert hat
b?
Antwort:
Dieser Code führt zu UB, da die Variable a geändert und gelesen wird, ohne dass es eine Reihenfolge von Sequenzpunkten (sequence points) zwischen den Operationen gibt. Der Standard garantiert kein bestimmtes Ergebnis, und der Compiler kann jedes Ergebnis erhalten oder sogar unerwarteten Code generieren.
Geschichte In einem Projekt für ein Datenspeichersystem hat einer der Entwickler einen Array-Out-of-Bounds-Zugriff in einer Low-Level-Funktion zugelassen. UB trat nur bei bestimmten Benutzerdaten auf und führte zur Zerstörung der Dateistruktur und zum Datenverlust bei den Kunden.
Geschichte In einem Projekt für Mikrocontroller traten Konstrukte mit dem Lesen von nicht initialisierten Variablen auf. Die Tests bestanden, aber ein Jahr nach dem Markteintritt des Geräts traten zufällige Fehler im Betrieb auf, die durch UB verursacht wurden: Variablen enthielten manchmal Müllwerte.
Geschichte In einem großen Open-Source-Projekt wurde ein Deskriptor entdeckt, der aus verschiedenen Teilen des Codes zweimal freigegeben wurde. Dieses UB trat zunächst sehr selten auf, führte jedoch in neuen Versionen des Betriebssystems zu häufigen Abstürzen.