LESSON 36 · ADVANCED4 min read

Dynamic Analysis: AddressSanitizer, UndefinedBehaviorSanitizer, and Valgrind

Detect systems vulnerabilities at runtime: AddressSanitizer (-fsanitize=address), UBSan (-fsanitize=undefined), ThreadSanitizer, shadow memory, and Valgrind Memcheck.

C++20 / C++23Free to readModule 9 of 11
YOUR NEXT SMALL WINS

By the end, you’ll be able to…

  • Instrument binaries with LLVM/GCC AddressSanitizer (ASan) to catch buffer overflows and use-after-free
  • Detect signed integer overflows, null dereferencing, and misaligned pointers using UBSan
  • Inspect shadow memory architecture and contrast compile-time sanitizers with Valgrind VM emulation

01The Role of Dynamic Analysis in Systems C++

C++ prioritizes performance over safety: the compiler does not emit runtime bounds checks or garbage collection safeguards. A minor programming mistake—such as reading 1 byte past an array boundary, reading uninitialized memory, or accessing a dangling pointer—triggers Undefined Behavior (UB).

Undefined behavior is insidious because it may appear to work in local testing, but crashes catastrophically under production loads or creates critical remote code execution (RCE) security vulnerabilities.

Dynamic Analysis Sanitizers—developed by Google and integrated directly into Clang and GCC—instrument compiled machine code with lightweight validation hooks that trap and diagnose memory errors the instant they occur at runtime.

terminalShell
# Compile with AddressSanitizer and UndefinedBehaviorSanitizerg++ -O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer main.cpp -o app# Compile with ThreadSanitizer to detect data racesg++ -O1 -g -fsanitize=thread -fno-omit-frame-pointer server.cpp -o server

02AddressSanitizer (ASan) and Shadow Memory

AddressSanitizer (-fsanitize=address) detects: Out-of-bounds array access (stack, heap, and global), Use-After-Free (accessing deleted pointers), Double Free, and Memory Leaks.

ASan achieves extreme speed (~2x slowdown compared to Valgrind's 20x slowdown) through an ingenious architecture: Shadow Memory.

ASan maps every 8 bytes of virtual memory to 1 byte of shadow memory. When memory is allocated, redzones (poisoned memory guards) are placed around the allocation in shadow memory. Every load and store instruction is instrumented with a bit check against shadow memory. If an instruction touches a poisoned redzone, ASan halts the program immediately and outputs a detailed stack trace.

03UndefinedBehaviorSanitizer (UBSan) and TSan

UndefinedBehaviorSanitizer (-fsanitize=undefined) traps non-memory undefined behaviors: signed integer overflow, null pointer dereferences, bit shifts exceeding type width (e.g. 1 << 35 on 32-bit int), and misaligned pointer reads.

ThreadSanitizer (-fsanitize=thread) monitors inter-thread memory access to detect Data Races: two threads accessing the same memory concurrently where at least one thread is a writer without mutex synchronization.

Note: TSan cannot be combined with ASan in the same compilation run; they must be executed in separate testing passes.

04Sanitizer Comparison Matrix

Comparing dynamic analysis tools in modern C++ CI/CD test pipelines:

Always run your automated unit and integration test suites with ASan and UBSan enabled.

notes.txtPlain text
+-----------------------+---------------------+-------------------+-------------------------+| Tool                  | Compiler Flag       | Primary Detection | Typical Slowdown        |+-----------------------+---------------------+-------------------+-------------------------+| AddressSanitizer      | -fsanitize=address  | Out-of-bounds/UAF | ~2x (Fast)              || UndefinedBehaviorSan  | -fsanitize=undefined| Overflow, null, UB| ~1.2x (Near-native)     || ThreadSanitizer       | -fsanitize=thread   | Data races        | ~3x - 5x                || Valgrind Memcheck     | External tool       | Memory leaks, UAF | ~20x - 50x (Very slow)  |+-----------------------+---------------------+-------------------+-------------------------+

05Production Systems Architecture & Hardware Trade-Offs

From an operating system and hardware architecture perspective, systems software must account for physical execution realities that compiler abstractions intentionally hide. At the hardware level, instruction caches (I-Cache) and data caches (D-Cache) operate independently, and CPU pipeline front-ends rely heavily on branch target buffers (BTB) to minimize instruction fetch stalls. When code is organized into coherent, spatially contiguous blocks within translation units, binary code density increases, improving instruction cache hit rates across high-frequency execution loops.

Furthermore, modern linkers such as LLVM lld and mold perform Link-Time Optimization (LTO) across translation units. When LTO is enabled (-flto), the compiler writes LLVM bitcode into object files rather than final machine code, allowing the linker to perform cross-translation-unit function inlining, devirtualization, and dead-code stripping across the entire binary.

LET IT CLICK

The ideas worth keeping.

  • Dynamic sanitizers instrument binaries to catch memory errors and undefined behavior at runtime.
  • AddressSanitizer uses shadow memory to detect buffer overflows and use-after-free bugs with minimal overhead.
  • ThreadSanitizer detects multi-threaded data races before they cause silent production corruption.
TURN UNDERSTANDING INTO SOMETHING YOU CAN DO

Make it yours.

Type and test your code right here in the interactive workspace. Run your solution, check the output, and compare with the worked guide when ready.

01

Exercise 1: Write the compilation command to compile a te

Write the compilation command to compile a test suite test_suite.cpp with debug symbols, AddressSanitizer, and UndefinedBehaviorSanitizer using g++.

your_turn_1.cpp⚙️C++
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.
Explore a worked solution
one_possible_solution.cppC++
g++ -std=c++20 -O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer test_suite.cpp -o test_suite

Include -g, -O1, -fsanitize=address,undefined, and -fno-omit-frame-pointer.

02

Exercise 2: Explain how ASan uses shadow memory and re

Explain how ASan uses 'shadow memory' and 'redzones' to catch buffer overflows in arrays.

your_turn_2.cpp⚙️C++
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.
Explore a worked solution
one_possible_solution.cppC++
// ASan maps every 8 bytes of application memory to 1 byte of shadow memory.// When an array is allocated, ASan surrounds the buffer with poisoned 'redzone' bytes.// The compiler instruments every memory access with a shadow byte check.// If an index accesses memory beyond the array, it hits the redzone,// triggering an immediate crash report with exact line numbers and memory dumps.

Redzones surround buffers, and shadow memory records whether bytes are valid or poisoned.

A SMALL QUESTION. A USEFUL NEXT STEP.

What stayed with you?

Check the ideas while they’re fresh. Your answers stay in this page and feedback appears as you go.

A LITTLE ACTIVE RECALL0 / 3 answered
01What is the typical performance overhead of AddressSanitizer (ASan) compared to Valgrind Memcheck?
02Which sanitizer detects data races between concurrent threads accessing unsynchronized memory?
03What does UndefinedBehaviorSanitizer (UBSan) detect?
⚡CODING CHALLENGE
🔒Required to Mark Lesson Complete

Exercise 1: Write the compilation command to compile a te

Write the compilation command to compile a test suite test_suite.cpp with debug symbols, AddressSanitizer, and UndefinedBehaviorSanitizer using g++.

EXPECTED OUTPUT
Build completed. Binary executed.
[Exit code: 0]
main.cppC++
Ctrl + ↵
Execution Console
Click "Run & Verify" (or press Ctrl + Enter) to test your code against the challenge.

Keep exploring.

The official references behind this lesson, when you want a second angle or the full details.

MODULE 09 · PRACTICAL SELF-CHECK

Pause. Put the pieces together.

You’ve reached the end of Systems Error Handling, std::expected, and Sanitizers. Before moving on, use this task to check what you can do independently.

Build exception-free monadic error pipelines and run test suites under AddressSanitizer.

Try it in your own environment and write down the result. This is a self-check; reading completion does not evaluate your code.

Review this module

One lesson closer.

Reading is a start. Trying it yourself makes the connection.

Solve the hands-on coding challenge in the knowledge section to verify your code and unlock lesson completion.