Undefined Behavior
int, or whether char is signed) is unspecified by the standard but each compiler must document and consistently apply some defined behavior. Undefined behavior has no such guarantee — a program can behave differently between two runs, two optimization levels, or even two lines of the same function.Classic Sources of Undefined Behavior
Source | Example |
|---|---|
Signed integer overflow |
|
Dereferencing NULL or a dangling pointer | Reading or writing through a pointer after |
Out-of-bounds array access |
|
Using an uninitialized variable |
|
Modifying a variable twice without a sequence point |
|
Strict aliasing violations | Accessing the same memory through two unrelated pointer types, e.g. reinterpreting a |
Division by zero |
|
Shifting by an out-of-range amount |
|
Why It Is So Dangerous
// A "defensive" NULL check that a compiler may remove entirely.
void process(int *p) {
int value = *p; // if p is NULL, this line is already UB
if (p == NULL) { // the compiler may reason: "we already
return; // dereferenced p above, so if we reached
} // this line, p can't have been NULL" --
// and delete this whole check!
printf("%d\n", value);
}Signed Overflow: A Concrete Trap
#include <limits.h>
#include <stdio.h>
int main(void) {
int x = INT_MAX;
int y = x + 1; // undefined behavior -- NOT guaranteed to wrap to INT_MIN
printf("%d\n", y);
return 0;
}x + 1 > x is always true for a signed int and optimize a loop bound check away entirely, producing an infinite loop where none was intended.Tools That Help Catch UB
Compiler warnings (
-Wall -Wextra -Wpedantic) catch some UB patterns at compile time -- see the Compiler Warnings pageUndefinedBehaviorSanitizer (
-fsanitize=undefined) instruments a build to detect UB at runtime and print exactly where it happenedAddressSanitizer (
-fsanitize=address) catches memory-related UB such as out-of-bounds access and use-after-freeValgrind can detect uninitialized reads, invalid memory access, and leaks without needing to recompile
Static analyzers (e.g.
clang --analyze, Coverity, cppcheck) can flag suspicious patterns before you ever run the program