Skip to main content
C Undefined Behavior

Undefined Behavior

Undefined behavior (UB) is C’s most dangerous feature. The compiler can do literally anything when UB occurs — including appearing to work perfectly for years until a compiler upgrade, optimization flag change, or different input triggers a spectacular failure. The insidious part: UB does not mean “your program crashes.” It means the C standard places no requirements whatsoever on what happens. Your program might print the right answer, format your hard drive, send your browsing history to your boss, or (most commonly) work fine in debug builds and break silently in release builds. The only guarantee is that there are no guarantees.

Why Does C Have Undefined Behavior?

The Design Philosophy

Before looking at the dangers, understand why C was designed this way: The goal: Performance and portability above all else. Why UB exists:
  1. Performance: Checking for errors adds overhead.
    • Example: Checking array bounds on every access makes code 10-30% slower.
    • C’s philosophy: “Trust the programmer” - if you say arr[100], C assumes you know what you’re doing.
  2. Portability: Different hardware behaves differently.
    • Example: What happens when you right-shift a negative number?
    • x86: Arithmetic shift (preserves sign)
    • Some ARM/PowerPC: Logical shift (fills with zeros)
    • C’s solution: Make it “Implementation Defined” or “Undefined” so compilers can use the fastest native instruction.
  3. Optimization: The compiler assumes UB never happens.
    • Example: If you write x + 1, the compiler assumes no overflow.
    • This allows it to optimize loops and algebraic simplifications that wouldn’t be valid if it had to handle overflow wrapping.
The tradeoff: You get maximum speed and can run on any hardware, but you lose safety. C is a sharp tool - it cuts through problems efficiently, but can also cut you.

What is Undefined Behavior?

The C standard defines three categories of problematic code:
Undefined behavior is not just “unpredictable.” Modern compilers actively exploit UB for optimization. Code that “works” might break with a different compiler, optimization level, or even compiler version.
Common Undefined Behavior in C

Signed Integer Overflow


Null Pointer Dereference


Buffer Overflows


Use After Free


Uninitialized Variables


Strict Aliasing Violations


Sequence Point Violations


Shift Operators


Pointer Arithmetic Violations


Data Races


Division and Modulo


How Compilers Exploit UB

This is where undefined behavior goes from “academic concern” to “production nightmare.” Modern optimizing compilers do not just ignore UB — they actively exploit the assumption that UB never happens to generate faster code. When your code does trigger UB, the optimizer’s assumptions become wrong, and the generated code does something completely unrelated to what you wrote. Think of it like a contract: you promised the compiler your code would never have UB, and in exchange the compiler promised to make your code fast. When you break your side of the contract, the compiler’s optimizations — which were valid under the contract — produce nonsensical results.

Tools for Finding UB

Compiler Sanitizers

Valgrind

Static Analysis


Defensive Coding Practices

These are not optional “nice to have” habits — they are the minimum viable discipline for writing C code that works across compilers, optimization levels, and platforms. Every item on this list prevents a real class of bugs that has caused real security vulnerabilities in real production systems.

Exercises

1

UB Hunter

Find all undefined behavior in a provided code sample (at least 5 instances).
2

Safe Integer Library

Implement safe add, subtract, multiply, divide functions that detect overflow.
3

Sanitizer Setup

Set up a project with all sanitizers enabled in debug mode and run your data structures code through them.
4

Aliasing Exploration

Write code that behaves differently with -O0 vs -O2 due to strict aliasing, then fix it.

Next Up

System Calls & POSIX

Interface with the operating system