# Undefined Behaviour, Sanitizers and Common Bugs — C++

Source: https://www.skillbyai.com/en/cpp/a-ub

> Recognise undefined behaviour and catch bugs with warnings, sanitizers and tools.

## When the standard makes no promises

**Undefined behaviour (UB)** means the C++ standard places **no requirements** on what happens: the program may crash, appear to work, or behave differently with another compiler or optimisation level, because optimisers assume UB never happens. Common sources: **out-of-bounds** array or vector access with `[]`, **dereferencing null or dangling pointers**, **use after free**, **signed integer overflow**, **uninitialised variables**, **data races**, **double delete**, **invalid iterator use** after container modification, and **returning references to locals**. Defences: compile with warnings (`-Wall -Wextra`) and treat them as errors; use **sanitizers** in test builds, namely **AddressSanitizer** (`-fsanitize=address`) for memory errors, **UndefinedBehaviorSanitizer** (`-fsanitize=undefined`) for overflow and similar issues, and **ThreadSanitizer** (`-fsanitize=thread`) for data races; run **static analysers** such as clang-tidy; use `.at()` instead of `[]` where bounds are uncertain; and follow the **C++ Core Guidelines**. Many of these bugs disappear entirely when you use RAII, containers and references instead of raw pointers and manual memory.

## Bugs that sanitizers catch

Each line compiles; each is undefined behaviour.

```cpp
#include <climits>
#include <vector>

int main() {
    std::vector<int> v{1, 2, 3};
    int a = v[3];                 // out of bounds: UB (v.at(3) would throw instead)

    int* p = new int{5};
    delete p;
    int b = *p;                   // use after free: UB

    int big = INT_MAX;
    big = big + 1;                // signed overflow: UB

    int uninit;
    int c = uninit * 2;           // reading an uninitialised variable: UB
}

// build a test binary with sanitizers:
// g++ -std=c++20 -g -O1 -fsanitize=address,undefined -fno-omit-frame-pointer bugs.cpp -o bugs
// clang++ -std=c++20 -g -fsanitize=thread race.cpp -o race
```

## "It works on my machine" proves nothing

UB can stay hidden for years and appear only with a new compiler version or optimisation flag. Run tests regularly under AddressSanitizer and UndefinedBehaviorSanitizer in CI.

**Quiz:** Which tool detects out-of-bounds accesses and use-after-free at run time?

- [ ] ThreadSanitizer
- [ ] clang-format
- [x] AddressSanitizer
- [ ] The linker

*Answer:* AddressSanitizer. AddressSanitizer instruments memory accesses to catch these errors.
