AddressSanitizer — Clang 23.0.0git documentation
Clang 23.0.0git documentation
AddressSanitizer
Function Effect Analysis
::
Contents
::
ThreadSanitizer
AddressSanitizer
Introduction
AddressSanitizer is a fast memory error detector. It consists of a compiler
instrumentation module and a run-time library. The tool can detect the
following types of bugs:
Out-of-bounds accesses to heap, stack and globals
Use-after-free
Use-after-return (clang flag
-fsanitize-address-use-after-return=(never|runtime|always)
default:
runtime
Enable with:
ASAN_OPTIONS=detect_stack_use_after_return=1
(already enabled on Linux).
Disable with:
ASAN_OPTIONS=detect_stack_use_after_return=0
Use-after-scope (clang flag
-fsanitize-address-use-after-scope
Double-free, invalid free
Memory leaks (experimental)
Typical slowdown introduced by AddressSanitizer is
2x
How to build
Build LLVM/Clang with
CMake
and enable
the
compiler-rt
runtime. An example CMake configuration that will allow
for the use/testing of AddressSanitizer:
cmake
-DCMAKE_BUILD_TYPE
Release
-DLLVM_ENABLE_PROJECTS
"clang"
-DLLVM_ENABLE_RUNTIMES
"compiler-rt"
to
source>/llvm
Usage
Simply compile and link your program with
-fsanitize=address
flag. The
AddressSanitizer run-time library should be linked to the final executable, so
make sure to use
clang
(not
ld
) for the final link step. When linking
shared libraries, the AddressSanitizer run-time is not linked, so
-Wl,-z,defs
may cause link errors (don’t use it with AddressSanitizer). To
get a reasonable performance add
-O1
or higher. To get nicer stack traces
in error messages add
-fno-omit-frame-pointer
. To get perfect stack traces
you may need to disable inlining (just use
-O1
) and tail call elimination
-fno-optimize-sibling-calls
).
cat
example_UseAfterFree.cc
int main(int argc, char **argv) {
int *array = new int[100];
delete [] array;
return array[argc]; // BOOM
Compile
and
link
clang++
-O1
-g
-fsanitize
address
-fno-omit-frame-pointer
example_UseAfterFree.cc
or:
Compile
clang++
-O1
-g
-fsanitize
address
-fno-omit-frame-pointer
-c
example_UseAfterFree.cc
Link
clang++
-g
-fsanitize
address
example_UseAfterFree.o
If a bug is detected, the program will print an error message to stderr and
exit with a non-zero exit code. AddressSanitizer exits on the first detected error.
This is by design:
This approach allows AddressSanitizer to produce faster and smaller generated code
(both by ~5%).
Fixing bugs becomes unavoidable. AddressSanitizer does not produce
false alarms. Once a memory corruption occurs, the program is in an inconsistent
state, which could lead to confusing results and potentially misleading
subsequent reports.
If your process is sandboxed and you are running on OS X 10.10 or earlier, you
will need to set
DYLD_INSERT_LIBRARIES
environment variable and point it to
the ASan library that is packaged with the compiler used to build the
executable. (You can find the library by searching for dynamic libraries with
asan
in their name.) If the environment variable is not set, the process will
try to re-exec. Also keep in mind that when moving the executable to another machine,
the ASan library will also need to be copied over.
Symbolizing the Reports
To make AddressSanitizer symbolize its output
you need to set the
ASAN_SYMBOLIZER_PATH
environment variable to point to
the
llvm-symbolizer
binary (or make sure
llvm-symbolizer
is in your
$PATH
):
ASAN_SYMBOLIZER_PATH
/usr/local/bin/llvm-symbolizer
./a.out
==9442== ERROR: AddressSanitizer heap-use-after-free on address 0x7f7ddab8c084 at pc 0x403c8c bp 0x7fff87fb82d0 sp 0x7fff87fb82c8
READ of size 4 at 0x7f7ddab8c084 thread T0
0x403c8c
in
main
example_UseAfterFree.cc:4
0x7f7ddabcac4d
in
__libc_start_main
??:0
0x7f7ddab8c084 is located 4 bytes inside of 400-byte region [0x7f7ddab8c080,0x7f7ddab8c210)
freed by thread T0 here:
0x404704
in
operator
delete
[](
void*
??:0
0x403c53
in
main
example_UseAfterFree.cc:4
0x7f7ddabcac4d
in
__libc_start_main
??:0
previously allocated by thread T0 here:
0x404544
in
operator
new
[](
unsigned
long
??:0
0x403c43
in
main
example_UseAfterFree.cc:2
0x7f7ddabcac4d
in
__libc_start_main
??:0
==9442== ABORTING
If that does not work for you (e.g. your process is sandboxed), you can use a
separate script to symbolize the result offline (online symbolization can be
force disabled by setting
ASAN_OPTIONS=symbolize=0
):
ASAN_OPTIONS
symbolize
./a.out
log
projects/compiler-rt/lib/asan/scripts/asan_symbolize.py
log
c++filt
==9442== ERROR: AddressSanitizer heap-use-after-free on address 0x7f7ddab8c084 at pc 0x403c8c bp 0x7fff87fb82d0 sp 0x7fff87fb82c8
READ of size 4 at 0x7f7ddab8c084 thread T0
0x403c8c
in
main
example_UseAfterFree.cc:4
0x7f7ddabcac4d
in
__libc_start_main
??:0
...
Note that on macOS you may need to run
dsymutil
on your binary to have the
file:line info in the AddressSanitizer reports.
Additional Checks
Initialization order checking
AddressSanitizer can optionally detect dynamic initialization order problems,
when initialization of globals defined in one translation unit uses
globals defined in another translation unit. To enable this check at runtime,
you should set environment variable
ASAN_OPTIONS=check_initialization_order=1
Note that this option is not supported on macOS.
Stack Use After Return (UAR)
AddressSanitizer can optionally detect stack use after return problems.
This is available by default, or explicitly
-fsanitize-address-use-after-return=runtime
).
To disable this check at runtime, set the environment variable
ASAN_OPTIONS=detect_stack_use_after_return=0
Enabling this check (
-fsanitize-address-use-after-return=always
) will
reduce code size. The code size may be reduced further by completely
eliminating this check (
-fsanitize-address-use-after-return=never
).
To summarize:
-fsanitize-address-use-after-return=
never
: Completely disables detection of UAR errors (reduces code size).
runtime
: Adds the code for detection, but it can be disabled via the
runtime environment (
ASAN_OPTIONS=detect_stack_use_after_return=0
).
always
: Enables detection of UAR errors in all cases. (reduces code
size, but not as much as
never
).
Container Overflow Detection
AddressSanitizer can detect overflows in containers with custom allocators
(such as std::vector) where the library developers have added calls into the
AddressSanitizer runtime to indicate which memory is poisoned etc.
Note that this feature is prone to false positives:
Partially poisoning objects on stack, e.g. for small string optimization, can
cause both false positives and negatives.
If the binary is partially AddressSanitizer instrumented, these
checks can cause false positives.
See
Disabling container overflow checks
for details on suppressing checks.
Memory leak detection
For more information on leak detector in AddressSanitizer, see
LeakSanitizer
. The leak detection is turned on by default on Linux,
and can be enabled using
ASAN_OPTIONS=detect_leaks=1
on macOS;
however, it is not yet supported on other platforms.
Issue Suppression
AddressSanitizer is not expected to produce false positives. If you see one,
look again; most likely it is a true positive!
Suppressing Reports in External Libraries
Runtime interposition allows AddressSanitizer to find bugs in code that is
not being recompiled. If you run into an issue in external libraries, we
recommend immediately reporting it to the library maintainer so that it
gets addressed. However, you can use the following suppression mechanism
to unblock yourself and continue on with the testing. This suppression
mechanism should only be used for suppressing issues in external code; it
does not work on code recompiled with AddressSanitizer. To suppress errors
in external libraries, set the
ASAN_OPTIONS
environment variable to point
to a suppression file. You can either specify the full path to the file or the
path of the file relative to the location of your executable.
ASAN_OPTIONS
suppressions
MyASan.supp
Use the following format to specify the names of the functions or libraries
you want to suppress. You can see these in the error report. Remember that
the narrower the scope of the suppression, the more bugs you will be able to
catch.
interceptor_via_fun:NameOfCFunctionToSuppress
interceptor_via_fun:-
ClassName
objCMethodToSuppress:
interceptor_via_lib:NameOfTheLibraryToSuppress
Conditional Compilation with
__has_feature(address_sanitizer)
In some cases one may need to execute different code depending on whether
AddressSanitizer is enabled.
__has_feature
can be used for
this purpose.
#if defined(__has_feature)
# if __has_feature(address_sanitizer)
// code that builds only under AddressSanitizer
# endif
#endif
Disabling Instrumentation with
__attribute__((no_sanitize("address")))
Some code should not be instrumented by AddressSanitizer. One may use
the attribute
__attribute__((no_sanitize("address")))
(which has
deprecated synonyms
no_sanitize_address
and
no_address_safety_analysis
) to disable instrumentation of a
particular function. This attribute may not be supported by other
compilers, so we suggest to use it together with
__has_feature(address_sanitizer)
The same attribute used on a global variable prevents AddressSanitizer
from adding redzones around it and detecting out of bounds accesses.
AddressSanitizer also supports
__attribute__((disable_sanitizer_instrumentation))
. This attribute
works similarly to
__attribute__((no_sanitize("address")))
, but it also
prevents instrumentation performed by other sanitizers.
Interaction of Inlining with Disabling Sanitizer Instrumentation
no_sanitize
function will not be inlined heuristically by the compiler into a sanitized function.
An
always_inline
function will adopt the instrumentation status of the function it is inlined into.
Forcibly combining
no_sanitize
and
__attribute__((always_inline))
is not supported, and will often lead to unexpected results. To avoid mixing these attributes, use:
// Note, __has_feature test for sanitizers is deprecated, and Clang will support __SANITIZE___ similar to GCC.
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) || ...
#define ALWAYS_INLINE_IF_UNINSTRUMENTED
#else
#define ALWAYS_INLINE_IF_UNINSTRUMENTED __attribute__((always_inline))
#endif
Explicit Sanitizer Checks with
__builtin_allow_sanitize_check
The
__builtin_allow_sanitize_check("address")
builtin can be used to
conditionally execute code depending on whether AddressSanitizer checks are
enabled and permitted by the current policy (after inlining). This is
particularly useful for inserting explicit, sanitizer-specific checks around
operations like syscalls or inline assembly, which might otherwise be unchecked
by the sanitizer.
Example:
void
__asan_load8
void
);
inline
__attribute__
((
always_inline
))
void
my_helper
void
addr
if
__builtin_allow_sanitize_check
"address"
))
__asan_load8
addr
);
// ... actual logic, e.g. inline assembly ...
asm
volatile
"..."
"r"
addr
"memory"
);
void
instrumented_function
()
...
my_helper
buf
);
// checks are active
...
__attribute__
((
no_sanitize
"address"
)))
void
uninstrumented_function
()
...
my_helper
buf
);
// checks are skipped
...
Disabling container overflow checks
Runtime suppression
Container overflow checks can be disabled at runtime using the
ASAN_OPTIONS=detect_container_overflow=0
environment variable.
Compile time suppression
-D__SANITIZER_DISABLE_CONTAINER_OVERFLOW__
can be used at compile time to
disable container overflow checks if the container library has added support
for this define.
To support a standard way to disable container overflow checks at compile time,
library developers should use this definition in conjunction with the
AddressSanitizer feature test to conditionally include container overflow
related code compiled into user code:
The recommended form is
// include the sanitizer common interfaces
#include

#if __has_feature(address_sanitizer)
// Container overflow detection enabled - include annotations
__sanitizer_annotate_contiguous_container
beg
end
old_mid
new_mid
);
#endif
This pattern ensures that:
Container overflow annotations are only included when AddressSanitizer is
enabled
Container overflow detection can be disabled by passing
-D__SANITIZER_DISABLE_CONTAINER_OVERFLOW__
to the compiler
Suppressing Errors in Recompiled Code (Ignorelist)
AddressSanitizer supports
src
and
fun
entity types in
Sanitizer special case list
, that can be used to suppress error reports
in the specified source files or functions. Additionally, AddressSanitizer
introduces
global
and
type
entity types that can be used to
suppress error reports for out-of-bound access to globals with certain
names and types (you may only specify class or struct types).
You may use an
init
category to suppress reports about initialization-order
problems happening in certain source files or with certain global variables.
# Suppress error reports for code in a file or in a function:
src:bad_file.cpp
# Ignore all functions with names containing MyFooBar:
fun:*MyFooBar*
# Disable out-of-bound checks for global:
global:bad_array
# Disable out-of-bound checks for global instances of a given class ...
type:Namespace::BadClassName
# ... or a given struct. Use wildcard to deal with anonymous namespace.
type:Namespace2::*::BadStructName
# Disable initialization-order checks for globals:
global:bad_init_global
init
type:*BadInitClassSubstring*
init
src:bad/init/files/*
init
Suppressing memory leaks
Memory leak reports produced by
LeakSanitizer
(if it is run as a part
of AddressSanitizer) can be suppressed by a separate file passed as
LSAN_OPTIONS
suppressions
MyLSan.supp
which contains lines of the form
leak:
. Memory leak will be
suppressed if pattern matches any function name, source file name, or
library name in the symbolized stack trace of the leak report. See
full documentation
for more details.
Code generation control
Instrumentation code outlining
By default AddressSanitizer inlines the instrumentation code to improve the
run-time performance, which leads to increased binary size. Using the
(clang flag
-fsanitize-address-outline-instrumentation
default:
false
flag forces all code instrumentation to be outlined, which reduces the size
of the generated code, but also reduces the run-time performance.
Limitations
AddressSanitizer uses more real memory than a native run. Exact overhead
depends on the allocation sizes. The smaller the allocations you make the
bigger the overhead is.
AddressSanitizer uses more stack memory. We have seen up to 3x increase.
On 64-bit platforms AddressSanitizer maps (but not reserves) 16+ Terabytes of
virtual address space. This means that tools like
ulimit
may not work as
usually expected.
Static linking of executables is not supported.
Security Considerations
AddressSanitizer is a bug detection tool and its runtime is not meant to be
linked against production executables. While it may be useful for testing,
AddressSanitizer’s runtime was not developed with security-sensitive
constraints in mind and may compromise the security of the resulting executable.
Supported Platforms
AddressSanitizer is supported on:
Linux
macOS
iOS Simulator
Android
NetBSD
FreeBSD
Windows 8.1+
Current Status
AddressSanitizer is fully functional on supported platforms starting from LLVM
3.1. The test suite is integrated into CMake build and can be run with
make
check-asan
command.
The Windows port is functional and is used by Chrome and Firefox, but it is not
as well supported as the other ports.
More Information
Function Effect Analysis
::
Contents
::
ThreadSanitizer
© Copyright 2007-2026, The Clang Team.
Created using
Sphinx
7.2.6.