ProgrammatieSysteemprogrammeur C++

Wat is ongedefinieerd gedrag (undefined behavior) in C++? Geef voorbeelden en leg uit hoe het te vermijden.

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord.

Ongedefinieerd gedrag (Undefined Behavior, UB) is een situatie waarin de standaard van de taal het gedrag van het programma niet definieert. De compiler kan met het programma doen wat hij maar wil: het programma kan crashen, onjuiste resultaten geven of zelfs 'werken'. UB ontstaat door fouten zoals het overschrijden van de array grenzen, dereferencen van een null pointer, enz.

Voorbeeld van expliciete UB:

int arr[5]; arr[10] = 42; // UB: overschrijding van array grenzen int* p = nullptr; *p = 1; // UB: dereferencen van 0

UB te vermijden is mogelijk door de standaarden na te leven, moderne tools te gebruiken (ASan, UBSan, valgrind), te proberen rauwe pointers niet te gebruiken en veilige code te schrijven.

Vraag met een valstrik.

Als UB in één deel van het programma optreedt, kan dit dan invloed hebben op een geheel ander, 'onafhankelijk' deel van de code?

Ja! De compiler kan tijdens optimalisatie onverwachte transformaties doen als hij ontdekt dat er UB is opgetreden.

Voorbeeld:

void foo(int* p) { if (p == nullptr) return; *p = 5; // Maar als p niet nullptr was, is dit UB! De compiler kan de controles verwijderen, aangezien hij denkt dat p altijd geldig is. }

Voorbeelden van echte fouten door onbekendheid met de nuances van het onderwerp.


Verhaal

Op de server van een groot bedrijf traden af en toe willekeurige crashes van het proces op door dereferencen van een null pointer, die moeilijk te reproduceren waren: in debug werkte alles, maar in release niet.


Verhaal

Bij het porteren van code van 32-bit naar 64-bit werden de datatypes door elkaar gehaald, en werd er gecast tussen int en pointer. Op de ene machines werkte het, terwijl er op andere machines crashes en vreemde artefacten verschenen.


Verhaal

Er is een geval op internet bekend waarbij onschuldige UB (overschrijding van de array) de werking van het hele programma verstoorde: de compiler verwijderde niet alleen de omgang met de array, maar 'optimaliseerde' ook een deel van de code dat niets met de fout te maken had.