AddressSanitizer runtime
The AddressSanitizer runtime library intercepts common memory allocation functions and operations to enable inspection of memory accesses. There are several different runtime libraries that support the various types of executables the compiler may generate. The compiler and linker automatically link the appropriate runtime libraries, as long as you pass the /fsanitize=address
option at compile time. You can override the default behavior by using the /NODEFAULTLIB
option at link time. For more information, see the section on linking in the AddressSanitizer language, build, and debugging reference.
When compiling with cl /fsanitize=address
, the compiler generates instructions to manage and check shadow bytes. Your program uses this instrumentation to check memory accesses on the stack, in the heap, or in the global scope. The compiler also produces metadata describing stack and global variables. This metadata enables the runtime to generate precise error diagnostics: function names, lines, and columns in your source code. Combined, the compiler checks and runtime libraries can precisely diagnose many types of memory safety bugs if they're encountered at run-time.
The list of runtime libraries for linking to the AddressSanitizer runtime, as of Visual Studio 17.7 Preview 3, follows. For more information about the /MT
(statically link the runtime) and /MD
(dynamically link the redist at runtime) options, see /MD, /MT, /LD (Use Run-Time Library).
Note
In the following table, {arch}
is either i386
or x86_64
.
These libraries use Clang conventions for architecture names. MSVC conventions are normally x86
and x64
rather than i386
and x86_64
, but they refer to the same architectures.
CRT option | AddressSanitizer runtime library (.lib) | Address runtime binary (.dll) |
---|---|---|
/MT or /MTd |
clang_rt.asan_dynamic-{arch} , clang_rt.asan_static_runtime_thunk-{arch} |
clang_rt.asan_dynamic-{arch} |
/MD or /MDd |
clang_rt.asan_dynamic-{arch} , clang_rt.asan_dynamic_runtime_thunk-{arch} |
clang_rt.asan_dynamic-{arch} |
The following diagram shows how the language runtime libraries are linked for the /MT
, /MTd
, /MD
, and /MDd
compiler options:
The image shows three scenarios for linking the runtime library. The first is /MT or /MTd. My_exe.exe and my_dll.dll are both shown with their own copies of the statically linked VCRuntime, Universal CRT, and C++ runtimes. The scenarios show /MD in which both my_exe.exe and my_dll.dll share vcruntime140.dll, ucrtbase.dll, and msvcp140.dll. The last scenario shows /MDd in which both my_exe.exe and my_dll.dll share the debug versions of the runtimes: vcruntime140d.dll, ucrtbased.dll, and msvcp140d.dll
The following diagram shows how the ASan library is linked for various compiler options:
The image shows four scenarios for linking the ASan runtime library. The scenarios are for /MT (statically link the runtime), /MTd (statically link the debug runtime), /MD (dynamically link the redist at runtime), /MDd (dynamically link the debug redist at runtime). In all cases, my_exe.exe links and its associates my_dll.dll link to a single instance of clang-rt.asan-dynamix-x86_64.dll.
Even when statically linking, the ASan runtime DLL must be present at runtime--unlike other C Runtime components.
Previous versions
Before Visual Studio 17.7 Preview 3, statically linked (/MT
or /MTd
) builds didn't use a DLL dependency. Instead, the AddressSanitizer runtime was statically linked into the user's EXE. DLL projects would then load exports from the user's EXE to access ASan functionality.
Dynamically linked projects (/MD
or /MDd
) used different libraries and DLLs depending on whether the project was configured for debug or release. For more information about these changes and their motivations, see MSVC Address Sanitizer – One DLL for all Runtime Configurations.
The following table describes the previous behavior of the AddressSanitizer runtime library linking, before Visual Studio 17.7 Preview 3:
CRT option | DLL or EXE | DEBUG? | ASan library (.lib ) |
ASan runtime binary (.dll ) |
---|---|---|---|---|
/MT |
EXE | No | clang_rt.asan-{arch} , clang_rt.asan_cxx-{arch} |
None |
/MT |
DLL | No | clang_rt.asan_dll_thunk-{arch} |
None |
/MD |
Either | No | clang_rt.asan_dynamic-{arch} , clang_rt.asan_dynamic_runtime_thunk-{arch} |
clang_rt.asan_dynamic-{arch} |
/MT |
EXE | Yes | clang_rt.asan_dbg-{arch} , clang_rt.asan_dbg_cxx-{arch} |
None |
/MT |
DLL | Yes | clang_rt.asan_dbg_dll_thunk-{arch} |
None |
/MD |
Either | Yes | clang_rt.asan_dbg_dynamic-{arch} , clang_rt.asan_dbg_dynamic_runtime_thunk-{arch} |
clang_rt.asan_dbg_dynamic-{arch} |
The following diagram shows how the ASan library was linked for various compiler options before Visual Studio 2022 17.7 Preview 3:
The image shows four scenarios for linking the ASan runtime library. The scenarios are for /MT (statically link the runtime), /MTd (statically link the debug runtime), /MD (dynamically link the redist at runtime), /MDd (dynamically link the debug redist at runtime). For /MT, my_exe.exe has a statically linked copy of the ASan runtime. my_dll.dll links to the ASan runtime in my_exe.exe. For /MTd, the diagram is the same except it uses the debug statically linked ASan runtime. For /MD, both my_exe.exe and my_dll.dll link to the dynamically linked ASan runtime named clang_rt.asan_dynamic-x86_64.dll. For /MDd, the diagram is the same except my_exe.exe and my_dll.dll link to the debug ASan runtime named clang_rt.asan_dbg_dynamic-x86_64.dll.
Function interception
The AddressSanitizer achieves function interception through many hotpatching techniques. These techniques are best documented within the source code itself.
The runtime libraries intercept many common memory management and memory manipulation functions. For a list, see AddressSanitizer list of intercepted functions. The allocation interceptors manage metadata and shadow bytes related to each allocation call. Every time a CRT function such as malloc
or delete
is called, the interceptors set specific values in the AddressSanitizer shadow-memory region to indicate whether those heap locations are currently accessible and what the bounds of the allocation are. These shadow bytes allow the compiler-generated checks of the shadow bytes to determine whether a load or store is valid.
Interception isn't guaranteed to succeed. If a function prologue is too short for a jmp
to be written, interception can fail. If an interception failure occurs, the program throws a debugbreak
and halts. If you attach a debugger, it makes the cause of the interception issue clear. If you have this problem, report a bug.
Note
Users can optionally attempt to continue past a failed interception by setting the environment variable ASAN_WIN_CONTINUE_ON_INTERCEPTION_FAILURE
to any value. Continuing past an interception failure can result in missed bug reports for that function.
Custom allocators and the AddressSanitizer runtime
The AddressSanitizer runtime provides interceptors for common allocator interfaces, malloc
/free
, new
/delete
, HeapAlloc
/HeapFree
(via RtlAllocateHeap
/RtlFreeHeap
). Many programs make use of custom allocators for one reason or another, an example would be any program using dlmalloc
or a solution using the std::allocator
interface and VirtualAlloc()
. The compiler is unable to automatically add shadow-memory management calls to a custom allocator. It's the user's responsibility to use the provided manual poisoning interface. This API enables these allocators to function properly with the existing AddressSanitizer runtime and shadow byte conventions.
Manual AddressSanitizer poisoning interface
The interface for enlightening is simple, but it imposes alignment restrictions on the user. Users may import these prototypes by importing sanitizer/asan_interface.h
. Here are the interface function prototypes:
void __asan_poison_memory_region(void const volatile *addr, size_t size);
void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
For convenience, the AddressSanitizer interface header file provides wrapper macros. These macros check whether the AddressSanitizer functionality is enabled during compilation. They allow your source code to omit the poisoning function calls when they're not needed. These macros should be preferred over calling the above functions directly:
#define ASAN_POISON_MEMORY_REGION(addr, size)
#define ASAN_UNPOISON_MEMORY_REGION(addr, size)
Alignment requirements for AddressSanitizer poisoning
Any manual poisoning of shadow bytes must consider the alignment requirements. The user must add padding if necessary so the shadow bytes end on a byte boundary in the shadow memory. Each bit in the AddressSanitizer shadow memory encodes the state of a single byte in the application's memory. This encoding means the total size of each allocation, including any padding, must align to an 8-byte boundary. If the alignment requirement isn't satisfied, it can lead to incorrect bug reporting. The incorrect reporting could manifest as missing reports (false negatives) or reports on non-errors (false-positives).
For an illustration of the alignment requirement and potential issues, see the provided ASan alignment examples. One is a small program to show what can go wrong with manual shadow memory poisoning. The second is an example implementation of manual poisoning using the std::allocator
interface.
Run-time options
Microsoft C/C++ (MSVC) uses a runtime based on the Clang AddressSanitizer runtime from the llvm-project repository. Because of this, most runtime options are shared between the two versions. A complete list of the public Clang runtime options is available here. We document some differences in the sections that follow. If you discover options that don't function as expected, report a bug.
Unsupported AddressSanitizer options
- detect_container_overflow
- unmap_shadow_on_exit
Note
The AddressSanitizer runtime option halt_on_error
doesn't function the way you might expect. In both the Clang and the MSVC runtime libraries, many error types are considered non-continuable, including most memory corruption errors.
For more information, see the Differences with Clang 12.0 section.
MSVC-specific AddressSanitizer runtime options
windows_hook_legacy_allocators
Boolean, set tofalse
to disable interception ofGlobalAlloc
andLocalAlloc
allocators.Note
The option
windows_hook_legacy_allocators
wasn't available in the public llvm-project runtime when this article was written. The option may eventually be contributed back to the public project; however, it's dependent on code review and community acceptance.The option
windows_hook_rtl_allocators
, previously an opt-in feature while AddressSanitizer was experimental, is now enabled by default. In versions before Visual Studio 2022 version 17.4.6, the default option value isfalse
. In Visual Studio 2022 version 17.4.6 and later versions, the optionwindows_hook_rtl_allocators
defaults totrue
.iat_overwrite
String, set to"error"
by default. Other possible values are"protect"
and"ignore"
. Some modules may overwrite theimport address table
of other modules to customize implementations of certain functions. For example, drivers commonly provide custom implementations for specific hardware. Theiat_overwrite
option manages the AddressSanitizer runtime's protection against overwrites for specificmemoryapi.h
functions. The runtime currently tracks theVirtualAlloc
,VirtualProtect
, andVirtualQuery
functions for protection. This option is available in Visual Studio 2022 version 17.5 Preview 1 and later versions. The followingiat_overwrite
values control how the runtime reacts when protected functions are overwritten:- If set to
"error"
(the default), the runtime reports an error whenever an overwrite is detected. - If set to
"protect"
, the runtime attempts to avoid using the overwritten definition and proceeds. Effectively, the originalmemoryapi
definition of the function is used from inside the runtime to avoid infinite recursion. Other modules in the process still use the overwritten definition. - If set to
"ignore"
, the runtime doesn't attempt to correct any overwritten functions and proceeds with execution.
- If set to
windows_fast_fail_on_error
Boolean (false by default), set totrue
to enable the process to terminate with a __fastfail(71) after printing the error report.
Note
When abort_on_error value is set to true, on Windows the program terminates with an exit(3). In order to not change current behavior we decided to introduce this new option instead. If both abort_on_error and windows_fast_fail_on_error are true, the program will exit with the __fastfail.
AddressSanitizer list of intercepted functions (Windows)
The AddressSanitizer runtime hotpatches many functions to enable memory safety checks at runtime. Here's a non-exhaustive list of the functions that the AddressSanitizer runtime monitors.
Default interceptors
__C_specific_handler
(x64 only)_aligned_free
_aligned_malloc
_aligned_msize
_aligned_realloc
_calloc_base
_calloc_crt
_calloc_dbg
(debug runtime only)_except_handler3
(x86 only)_except_handler4
(x86 only) (undocumented)_expand
_expand_base
(undocumented)_expand_dbg
(debug runtime only)_free_base
(undocumented)_free_dbg
(debug runtime only)_malloc_base
(undocumented)_malloc_crt
(undocumented)_malloc_dbg
(debug runtime only)_msize
_msize_base
(undocumented)_msize_dbg
(debug runtime only)_realloc_base
(undocumented)_realloc_crt
(undocumented)_realloc_dbg
(debug runtime only)_recalloc
_recalloc_base
(undocumented)_recalloc_crt
(undocumented)_recalloc_dbg
(debug runtime only)_strdup
atoi
atol
calloc
CreateThread
free
frexp
longjmp
malloc
memchr
memcmp
memcpy
memmove
memset
RaiseException
realloc
RtlAllocateHeap
RtlCreateHeap
RtlDestroyHeap
RtlFreeHeap
RtlRaiseException
RtlReAllocateHeap
(undocumented)RtlSizeHeap
(undocumented)SetUnhandledExceptionFilter
strcat
strchr
strcmp
strcpy
strcspn
strdup
strlen
strncat
strncmp
strncpy
strnlen
strpbrk
strspn
strstr
strtok
strtol
wcslen
wcsnlen
Optional interceptors
The interceptors listed here are only installed when an AddressSanitizer runtime option is enabled. Set windows_hook_legacy_allocators
to false
to disable legacy allocator interception.
set ASAN_OPTIONS=windows_hook_legacy_allocators=false
GlobalAlloc
GlobalFree
GlobalHandle
GlobalLock
GlobalReAlloc
GlobalSize
GlobalUnlock
LocalAlloc
LocalFree
LocalHandle
LocalLock
LocalReAlloc
LocalSize
LocalUnlock
See also
AddressSanitizer overview
AddressSanitizer known issues
AddressSanitizer build and language reference
AddressSanitizer shadow bytes
AddressSanitizer cloud or distributed testing
AddressSanitizer debugger integration
AddressSanitizer error examples