debugging · medium
Debugging: ASAN/TSAN/LSAN/UBSan — Runtime Memory and Race Detection
Sanitizers are compiler-instrumented runtime checks. ASAN (-fsanitize=address): shadow memory marks every byte; catches use-after-free, heap/stack overflow, double-free, global buffer overflow. Output shows: bad access, free site (root cause), allocation site. TSAN (-fsanitize=thread): tracks every memory access by thread and lock held; reports data races with both threads and lines. Cannot combine with ASAN. LSAN (part of ASAN): post-exit walk finds unreachable allocations. UBSan (-fsanitize=undefined): catches signed integer overflow, null deref, misalignment, shift OOB. CI strategy: ASAN+UBSan job (one build) + TSAN job (separate) — both must pass on PR. Only async-signal-safe functions are safe in signal handlers (printf is NOT).
ASAN: -fsanitize=address — catches UAF, overflow, double-free (2x slow); TSAN: -fsanitize=thread — catches data races (5x slow; separate job from ASAN); UBSan: -fsanitize=undefined — catches signed overflow, null deref, misalignment; run all on every PR in CI.
The code
# AddressSanitizer (ASAN) — heap/stack/global memory errorsg++ -g -O1 -fsanitize=address -fno-omit-frame-pointer -o app main.cpp# Detects: use-after-free, heap overflow, stack overflow,# double-free, use-after-return, global buffer overflow
# ThreadSanitizer (TSAN) — data racesg++ -g -O1 -fsanitize=thread -o app main.cpp# Detects: unsynchronized concurrent read/write of same memory
# LeakSanitizer (LSAN) — memory leaks (part of ASAN by default)ASAN_OPTIONS=detect_leaks=1 ./app# Or standalone: -fsanitize=leak
# UBSan — undefined behaviorg++ -g -O1 -fsanitize=undefined -o app main.cpp# Detects: signed int overflow, null pointer deref, shift OOB,# misaligned access, divide by zero
# Combine ASAN + UBSan (NOT with TSAN — they conflict!)g++ -g -O1 -fsanitize=address,undefined -o app main.cpp
# CI integration: add to your test build# cmake: -DCMAKE_CXX_FLAGS='-fsanitize=address,undefined'# 2-5x slowdown; only for testing, not production
# ASAN typical output format:# ==1234==ERROR: AddressSanitizer: heap-use-after-free# READ of size 4 at 0x... thread T0# #0 0x... in MyClass::use() my_class.cpp:47# #1 0x... in main() main.cpp:12# previously FREED at:# #0 0x... in operator delete my_class.cpp:31What this lesson walks through
- 01ASAN — AddressSanitizer catches memory corruption
- 02Heap use-after-free — ASAN output decoded
- 03TSAN — ThreadSanitizer catches data races
- 04LSAN — LeakSanitizer finds memory leaks
- 05UBSan — undefined behavior sanitizer
- 06CI integration — sanitizers on every PR
ASAN instruments every memory access at compile time. It maintains a shadow memory map that tracks which bytes are valid. On every load/store it checks the shadow byte — if the byte is poisoned (freed, out-of-bounds) it reports immediately with a full stack trace. 2x slower, but catches bugs that crash randomly in production.
See it animated — step by step, at your own pace
Unlock the full interactive walkthrough of Debugging: ASAN/TSAN/LSAN/UBSan — Runtime Memory and Race Detection and 100+ animated C++ interview lessons.