AddressSanitizer — Clang 22.1.8 documentation

# Clang 22.1.8 documentation

## 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" <path 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
        #0 0x403c8c in main example_UseAfterFree.cc:4
        #1 0x7f7ddabcac4d in __libc_start_main ??:0
    0x7f7ddab8c084 is located 4 bytes inside of 400-byte region [0x7f7ddab8c080,0x7f7ddab8c210)
    freed by thread T0 here:
        #0 0x404704 in operator delete[](void*) ??:0
        #1 0x403c53 in main example_UseAfterFree.cc:4
        #2 0x7f7ddabcac4d in __libc_start_main ??:0
    previously allocated by thread T0 here:
        #0 0x404544 in operator new[](unsigned long) ??:0
        #1 0x403c43 in main example_UseAfterFree.cc:2
        #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=0 ./a.out 2> 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
        #0 0x403c8c in main example_UseAfterFree.cc:4
        #1 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=<mode>`

  - `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.

In environments where not all the process binaries can be recompiled with AddressSanitizer enabled, 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.

### Conditional Sanitizer Checks with `__builtin_allow_sanitize_check`

The `__builtin_allow_sanitize_check("address")` builtin can be used to conditionally execute code only when AddressSanitizer is active for the current function (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:

    inline __attribute__((always_inline))
    void copy_to_device(void *addr, size_t size) {
      if (__builtin_allow_sanitize_check("address")) {
        // Custom checks that address range is valid.
      }
      // ... actual device memory copy logic, potentially a syscall ...
    }

    void instrumented_function() {
      ...
      copy_to_device(buf, sizeof(buf)); // checks are active
      ...
    }

    __attribute__((no_sanitize("address")))
    void uninstrumented_function() {
      ...
      copy_to_device(buf, sizeof(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 <sanitizer/common_interface_defs.h>

    #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:<pattern>. 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

https://github.com/google/sanitizers/wiki/AddressSanitizer