Diagnosing LLVM AddressSanitizer False Positives at -O2 and Higher
Diagnose LLVM AddressSanitizer false positives that appear only at -O2 or higher, with steps to distinguish optimization artifacts from real memory errors.
30 Aug 2026, 01:53 UTC

Recognizable Condition
When building a C/C++ project with LLVM's AddressSanitizer (-fsanitize=address) and optimization level -O2 or higher, the sanitizer may emit reports such as heap-use-after-free or stack-buffer-overflow for code that passes manual inspection and unit tests.
Cause / Diagnostic Indicators
| Possible Cause | What to Look For |
|---|---|
| Optimization removes ASan redzone poisoning | Report appears only with -O2/-O3 and disappears at -O0. |
| Inline assembly or intrinsics with unknown side effects | Report points to an asm volatile block or a compiler intrinsic (__builtin_*) that accesses memory. |
| Link‑time optimization (LTO) changes stack layout | Report occurs only when -flto is used; the stack address in the report does not match any local variable in the source. |
Ordered Checks
Confirm the symptom at the current optimization level. Build the translation unit (TU) with
-O2 -fsanitize=address(or the flags used in your CI) and run the test that triggers the report. Note the exact error message and address.# Run in the project build directory; needs read/write access to the source tree. $ clang++ -O2 -fsanitize=address -g -o myprog myprog.cpp $ ./myprog # or run the test suiteRequired permission: normal user account that can execute the binary. Risk: if the report reflects a real bug, executing may crash or corrupt data.
Reproduce with optimizations disabled to see if the report is an optimization artifact.
$ clang++ -O0 -fsanitize=address -g -o myprog0 myprog.cpp $ ./myprog0If the report disappears, the issue is likely optimization‑related.
Force full ASan instrumentation to rule out selective inlining thresholds.
$ clang++ -O2 -fsanitize=address -mllvm -asan-instrumentation-with-call-threshold=0 -g -o myprog_full myprog.cpp $ ./myprog_fullIf the report changes (e.g., disappears or moves), the original report was likely caused by a function being considered “cold” and not fully instrumented.
Check for inline assembly or intrinsics in the reported source.
Look at the source line indicated in the ASan output. If it contains
asm volatile,__asm__, or intrinsics such as_mm_loadu_si128, temporarily replace it with a pure C/C++ equivalent and rebuild.Test the effect of LTO.
$ clang++ -O2 -flto -fsanitize=address -g -o myprog_lto myprog.cpp $ ./myprog_ltoCompare the report with and without
-flto. A change in the reported stack address or its disappearance indicates an LTO‑related layout shift.
Fixes Tied to Findings
Optimization removed redzone poisoning
If the report vanishes at -O0 and returns with -O2, the most common remedy is to prevent the specific optimization that eliminates the redzone for the problematic function.
- Mark the function as
noinlineoroptnone:__attribute__((noinline)) void vulnerable_func(char *p) { // ... code that ASan flagged } - Alternatively, lower the optimization level for that TU only:
# In the build system (e.g., CMake) set_source_files_properties(myprog.cpp PROPERTIES COMPILE_FLAGS -O0 -fsanitize=address)Re‑build and verify the report disappears.
- Replace the assembly with intrinsics or standard library calls that have defined semantics.
- If the assembly is unavoidable, annotate it with
__attribute__((no_sanitize_address))to exclude that region from ASan checks:__attribute__((no_sanitize_address)) static void asm_copy(void *dst, const void *src, size_t n) { asm volatile ("movl %0, %%eax; ..." : : "r"(dst), "r"(src), "r"(n) : "memory"); }Re‑compile and confirm the report no longer appears for that line.
- Disable LTO for the affected TU:
set_source_files_properties(myprog.cpp PROPERTIES COMPILE_FLAGS -fno-lto -fsanitize=address) - If LTO is required for performance, isolate the problematic code in a separate compilation unit compiled without LTO and link it with the LTO‑enabled objects.
- Alternatively, upgrade to a newer LLVM/Clang version (≥ 13) where the interaction between LTO and ASan was improved; the ASan pass now runs after LTO optimizations.
- The report persists after applying the above fixes and also appears at
-O0. - The error address points to a legitimate object (e.g., a known heap allocation) and the access pattern matches a real use‑after‑free or overflow.
- Disabling ASan for the TU hides the symptom but the underlying functionality exhibits crashes or memory corruption in production builds (without sanitizers).
Inline assembly / intrinsics with unknown side effects
When the ASan pointer points inside an asm volatile block, the compiler cannot track the memory accessed, causing false positives.
LTO‑induced stack layout changes
LTO can merge functions and alter the relative order of stack slots, breaking ASan’s expectations of redzone placement.
Escalation Criteria
Proceed to deeper investigation when:
In these cases, treat the finding as a potential real bug: run a memory‑debugger such as Valgrind or AddressSanitizer with -fsanitize=address -fno-omit-frame-pointer on a debug build, and consider adding unit tests that exercise the suspect code paths.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.