LLVM Built-in Sanitizers: A Complete Guide to Enabling AddressSanitizer
AddressSanitizer detects memory errors like use-after-free and buffer overflows when you compile C++ code with the -fsanitize=address flag and link against the compiler-rt runtime library.
The llvm/llvm-project repository provides a suite of runtime sanitizers integrated directly into the Clang compiler driver. These tools instrument your code during compilation to catch bugs at runtime, with the complete catalog defined in clang/include/clang/Basic/Sanitizers.def.
What Are LLVM Built-in Sanitizers?
LLVM built-in sanitizers are runtime checking tools embedded in the compiler toolchain. Each sanitizer is identified by a string passed to the -fsanitize= command-line option, which the driver expands into specific LLVM IR instrumentation passes and links the matching runtime library from compiler-rt.
The canonical list resides in clang/include/clang/Basic/Sanitizers.def, where each entry follows the pattern SANITIZER("name", Identifier). You activate any sanitizer by passing its identifier to Clang.
Common built-in sanitizers include:
- address: Detects out-of-bounds heap/stack/global accesses, use-after-free, and double-free (AddressSanitizer).
- thread: Identifies data races using ThreadSanitizer.
- memory: Catches uninitialized memory reads with MemorySanitizer.
- leak: Finds memory leaks via LeakSanitizer (often bundled with ASan).
- undefined: Enables UndefinedBehaviorSanitizer checks for alignment violations, array-bounds, and integer overflow.
- hwaddress: Hardware-assisted AddressSanitizer using ARM Memory Tagging Extension (MTE).
How to Enable AddressSanitizer
Enabling AddressSanitizer requires a Clang built with the compiler-rt runtime and the correct compilation flags.
Build Requirements
First, ensure your LLVM/Clang build includes the sanitizers runtime. The sanitizer libraries live in the compiler-rt subproject. Configure CMake with:
cmake -DCMAKE_BUILD_TYPE=Release \
-DLLVM_ENABLE_PROJECTS="clang" \
-DLLVM_ENABLE_RUNTIMES="compiler-rt" \
/path/to/llvm-project/llvm
This builds the libclang_rt.asan runtime library required for instrumentation.
Compilation Flags
Compile your code with -fsanitize=address. Clang automatically injects instrumentation from llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp and links the ASan runtime from compiler-rt/lib/asan/.
Use these flags for optimal results:
clang++ -O1 -g -fsanitize=address -fno-omit-frame-pointer -c foo.cpp
clang++ -g -fsanitize=address foo.o -o foo
The -fno-omit-frame-pointer flag ensures accurate stack traces, while -O1 maintains reasonable performance without optimizing away the code you want to check.
Runtime Behavior and Configuration
When you run an ASan-instrumented binary, the runtime prints detailed error reports to stderr and aborts immediately on the first detected error. Expect approximately a 2× slowdown and increased memory usage proportional to allocation sizes.
Customize behavior via the ASAN_OPTIONS environment variable:
ASAN_OPTIONS=detect_stack_use_after_return=1:symbolize=0 ./program
Alternatively, define __asan_default_options() in your source code to set compile-time defaults.
Symbolizing Stack Traces
For readable file and line numbers, set ASAN_SYMBOLIZER_PATH to point to llvm-symbolizer:
ASAN_SYMBOLIZER_PATH=$(which llvm-symbolizer) ./program
Practical Example: Detecting Use-After-Free
Create a file named example_UseAfterFree.cc:
int main() {
int *arr = new int[10];
delete[] arr;
// Trigger use-after-free
return arr[5];
}
Compile and run:
clang++ -O1 -g -fsanitize=address -fno-omit-frame-pointer example_UseAfterFree.cc -o uaf
ASAN_SYMBOLIZER_PATH=$(which llvm-symbolizer) ./uaf
ASan outputs a detailed error report:
==1234==ERROR: AddressSanitizer heap-use-after-free on address 0x6020000000a0 ...
#0 0x40123a in main example_UseAfterFree.cc:5
#1 0x7f... in __libc_start_main ...
Summary
- LLVM sanitizers are defined in
clang/include/clang/Basic/Sanitizers.defand activated via-fsanitize=flags. - AddressSanitizer detects memory corruption bugs by instrumenting code in
llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp. - Enable ASan by compiling with
-fsanitize=addressand ensuring your Clang build includes thecompiler-rtruntime. - Use
ASAN_OPTIONSandASAN_SYMBOLIZER_PATHto configure runtime behavior and stack trace symbolization.
Frequently Asked Questions
What is the difference between AddressSanitizer and MemorySanitizer?
AddressSanitizer detects memory addressability issues like use-after-free and buffer overflows, while MemorySanitizer (-fsanitize=memory) detects reads of uninitialized memory. They use different instrumentation passes and runtime libraries, though both reside in compiler-rt.
Can I use AddressSanitizer in kernel space?
Yes. The KernelAddressSanitizer (KASan) is available via -fsanitize=kernel-address and is designed for kernel-mode code. It uses different runtime hooks than user-space ASan and requires specific kernel configuration options.
Why does my program abort immediately after the first ASan error?
This is by design. AddressSanitizer calls __asan::Abort() after printing the error report to prevent further corruption. You can disable this behavior for testing purposes by setting halt_on_error=0 in ASAN_OPTIONS, though continuing after memory corruption is generally unsafe.
How do I integrate AddressSanitizer into a CMake build?
Use the helper module in runtimes/cmake/Modules/GetSanitizerFlags.cmake or manually append -fsanitize=address to your CMAKE_CXX_FLAGS and CMAKE_C_FLAGS. Ensure you link against the compiler-rt runtime by verifying that LLVM_ENABLE_RUNTIMES includes compiler-rt in your toolchain build.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →