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:

Diagram of how the runtime libraries are linked for various 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:

Diagram of how the ASan runtime dll is linked.

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:

Diagram of how the ASan runtime dll was linked prior to Visual Studio 2022 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 to false to disable 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. In versions before Visual Studio 2022 version 17.4.6, the default option value is false. In Visual Studio 2022 version 17.4.6 and later versions, the option windows_hook_rtl_allocators defaults to true.

  • iat_overwrite String, set to "error" by default. Other possible values are "protect" and "ignore". Some modules may overwrite the import address table of other modules to customize implementations of certain functions. For example, drivers commonly provide custom implementations for specific hardware. The iat_overwrite option manages the AddressSanitizer runtime's protection against overwrites for specific memoryapi.h functions. The runtime currently tracks the VirtualAlloc, VirtualProtect, and VirtualQuery functions for protection. This option is available in Visual Studio 2022 version 17.5 Preview 1 and later versions. The following iat_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 original memoryapi 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.
  • windows_fast_fail_on_error Boolean (false by default), set to true 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

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

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