Comportamento indefinito (Undefined Behavior, UB) — è una situazione in cui lo standard del linguaggio non definisce il comportamento del programma. Il compilatore può fare qualsiasi cosa con il programma: il programma può bloccarsi, fornire risultati errati o persino 'funzionare'. L'UB si verifica a causa di errori come l'uscita dai limiti di un array, la dereferenziazione di un puntatore nullo, ecc.
int arr[5]; arr[10] = 42; // UB: uscita dai limiti dell'array int* p = nullptr; *p = 1; // UB: dereferenziazione di 0
Evitare l'UB è possibile seguendo gli standard, utilizzando strumenti moderni (ASan, UBSan, valgrind), cercando di non utilizzare puntatori grezzi e scrivendo codice sicuro.
Se l'UB si verifica in una parte del programma, può influenzare un'altra parte di codice 'indipendente'?
Sì! Il compilatore durante l'ottimizzazione può fare trasformazioni inaspettate se viene scoperto che si è verificato l'UB.
void foo(int* p) { if (p == nullptr) return; *p = 5; // E se p non era nullptr, questo è UB! Ma il compilatore può rimuovere i controlli, considerando che p è sempre valido. }
Storia
Su un server di una grande azienda a causa della dereferenziazione di un puntatore nullo, di tanto in tanto si verificavano crash casuali del processo, che erano difficili da riprodurre: in debug tutto funzionava, mentre in release — no.
Storia
Durante il porting del codice da 32-bit a 64-bit sono stati scambiati i tipi di dati, utilizzando il cast tra int e puntatore. Su alcune macchine funzionava, su altre si verificavano crash e strani artefatti.
Storia
In internet è noto un caso in cui un innocuo UB (uscita dai limiti dell'array) rompeva il funzionamento dell'intero programma: il compilatore ha rimosso non solo il lavoro con l'array, ma ha anche 'ottimizzato' parte del codice, non direttamente legata all'errore.