Each Clang sanitizer watches for one family of bug. AddressSanitizer finds memory errors, UndefinedBehaviorSanitizer finds undefined behavior such as signed overflow, MemorySanitizer finds uninitialized reads, and ThreadSanitizer finds data races. You usually cannot stack them all in one build, so you run several builds.
The four at a glance
- AddressSanitizer (
-fsanitize=address): out-of-bounds access, use-after-free, double free. About 2x slowdown. - UBSan (
-fsanitize=undefined): undefined behavior such as overflow, bad shifts and null use. Small runtime cost. - MemorySanitizer (
-fsanitize=memory): reads of uninitialized memory. About 3x slowdown. - ThreadSanitizer (
-fsanitize=thread): data races. About 5x to 15x slowdown.
The figures come from the Clang documentation for each tool.
UBSan: the cheap one to add
UBSan instruments code at compile time with a small runtime cost. Its checks include signed integer overflow, shifts, null pointer use, misaligned access, out-of-bounds array indexing and more. One detail trips people up: the undefined group does not include every check. The docs say it leaves out float-divide-by-zero, unsigned-integer-overflow, vptr and the nullability checks, so enable those by name if you want them.
By default most checks print a report and keep going. For fuzzing, add -fno-sanitize-recover so the first failure stops the run and gets saved as a crash.
MSan: powerful but demanding
MemorySanitizer detects uninitialized values used in branches, pointer accesses, or passed to and returned from functions. Its big requirement, in the docs' words: all program code must be instrumented, including libraries. A single uninstrumented dependency can cause false reports. That is why OSS-Fuzz lists the memory sanitizer as recommended but opt-in, requiring every dependency to be built with it.
Origin tracking, enabled with -fsanitize-memory-track-origins, shows where an uninitialized value came from, at an added cost of roughly 1.5x to 2x on top of the base slowdown.
TSan: for concurrent code
ThreadSanitizer finds data races, with documented overhead of about 5x to 15x time and 5x to 10x memory. It is marked beta in the docs and needs all code built with it for reliable results. Use it on tests that exercise threads, not on a parser fuzz target that runs single threaded.
How to combine them
- ASan and UBSan go together well, and many fuzzing setups use them as the default pair. OSS-Fuzz also defaults to address and undefined.
- MSan and TSan are separate builds. Do not try to link them with ASan.
- Each build is its own CI job with its own corpus runs.
None of them is for production
The Clang pages for ASan, MSan and TSan all say the runtimes are not meant for production executables. UBSan's docs say the full runtime is for testing, and for security-sensitive production builds suggest the minimal runtime or trap mode.
Quick check
Which sanitizer should I add first?
AddressSanitizer plus UBSan. They cover the most common C and C++ bugs at the lowest cost.
Why does MSan report bugs that are not real?
Usually because a library it calls was not built with MSan. Instrument every dependency, or the tool cannot tell initialized memory from uninitialized.
Sources
- Clang: AddressSanitizer
- Clang: UndefinedBehaviorSanitizer
- Clang: MemorySanitizer
- Clang: ThreadSanitizer
- OSS-Fuzz: new project guide
Last reviewed: 19 October 2026.