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.

Below is an inventory of runtime libraries for linking to the AddressSanitizer runtime, where {arch} is either i386 or x86_64.

Note

These libraries keep the Clang conventions for architecture names. The MSVC conventions are normally x86 and x64 rather than i386 and x86_64. They refer to the same architectures.

CRT option DLL or EXE DEBUG? AddressSanitizer runtime binaries libraries
MT EXE NO clang_rt.asan-{arch}, clang_rt.asan_cxx-{arch}
MT DLL NO clang_rt.asan_dll_thunk-{arch}
MD EITHER NO clang_rt.asan_dynamic-{arch}, clang_rt.asan_dynamic_runtime_thunk-{arch}
MT EXE YES clang_rt.asan_dbg-{arch}, clang_rt.asan_dbg_cxx-{arch}
MT DLL YES clang_rt.asan_dbg_dll_thunk-{arch}
MD EITHER YES clang_rt.asan_dbg_dynamic-{arch}, clang_rt.asan_dbg_dynamic_runtime_thunk-{arch}

When compiling with cl /fsanitize=address, the compiler generates instructions to manage and check the 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.

Function interception

The AddressSanitizer achieves function interception through many hot-patching 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 to true to enable interception of GlobalAlloc and LocalAlloc 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.

AddressSanitizer list of intercepted functions (Windows)

The AddressSanitizer runtime hot-patches 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

Optional interceptors

The interceptors listed here are only installed when an AddressSanitizer runtime option is enabled. Set windows_hook_legacy_allocators to true to enable legacy allocator interception. set ASAN_OPTIONS=windows_hook_legacy_allocators=true

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