Page 1 of 1

Using the Address Sanitizer

Posted: 2023年 Dec 1日 11:27
by Kyson

C/C++ is commonly used as the preferred programming language for embedded development. We always encountering memory errors during the development. Memory errors are extremely fatal issues, and once it occurs, usually cause program crashes. Memory errors is extremely difficult to debug.

Fortunately, we can use some tools to detect such errors. Using the built-in AddressSanitize feature of the compiler is the best solution.

Introduction

AddressSanitizer is a fast memory error detector, mainly used for C/C++ programs. It can detect common memory errors such as buffer overflow, use of uninitialized memory, and use of freed memory during runtime. From GCC 4.8, AddressSanitizer became a part of GCC. By using AddressSanitizer, we can detect and fix these memory error issues during the development, thereby improving the stability and security of the software.

Basic Usage

Since the compiler has built-in AddressSanitizer, it is very simple to use. Just add the -fsanitize=address and -fno-omit-frame-pointer flag to tell the compiler to add AddressSanitizer. This looks like:

Code: Select all

$ gcc -fsanitize=address -fno-omit-frame-pointer -g -o my_program my_program.c

Run it on the board. If there are memory errors in the program, AddressSanitizer will terminate the program when it detects an error and output detailed error information. We can locate the problem based on this information.

Note: AddressSanitizer depends on the libasan runtime library. If the board does not include this library, you need to find it in the toolchain folder and upload the library to the board.

Use after Free

Code: Select all

/**
 * $ gcc -fsanitize=address -fno-omit-frame-pointer -fsanitize-recover=address -g example_UseAfterFree.c -o example_UseAfterFree
 * $ ./example_UseAfterFree
 */
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
    int *array = (int *)malloc(100 * sizeof(int));
    free(array);
    return array[0];
}

Code: Select all

=================================================================
==22429==ERROR: AddressSanitizer: heap-use-after-free on address 0x614000000040 at pc 0x555c1cd8b22d bp 0x7ffda0b6ffc0 sp 0x7ffda0b6ffb0
READ of size 4 at 0x614000000040 thread T0
    #0 0x555c1cd8b22c in main /tmp/test/prog/asan_demo/example_UseAfterFree.c:11
    #1 0x7f68ae183082 in __libc_start_main ../csu/libc-start.c:308
    #2 0x555c1cd8b10d in _start (/tmp/test/prog/asan_demo/example_UseAfterFree+0x110d)

0x614000000040 is located 0 bytes inside of 400-byte region [0x614000000040,0x6140000001d0)
freed by thread T0 here:
    #0 0x7f68ae45e40f in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:122
    #1 0x555c1cd8b1f5 in main /tmp/test/prog/asan_demo/example_UseAfterFree.c:10
    #2 0x7f68ae183082 in __libc_start_main ../csu/libc-start.c:308

previously allocated by thread T0 here:
    #0 0x7f68ae45e808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
    #1 0x555c1cd8b1e5 in main /tmp/test/prog/asan_demo/example_UseAfterFree.c:9
    #2 0x7f68ae183082 in __libc_start_main ../csu/libc-start.c:308

SUMMARY: AddressSanitizer: heap-use-after-free /tmp/test/prog/asan_demo/example_UseAfterFree.c:11 in main
Shadow bytes around the buggy address:
  0x0c287fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c287fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c287fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c287fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c287fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c287fff8000: fa fa fa fa fa fa fa fa[fd]fd fd fd fd fd fd fd
  0x0c287fff8010: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c287fff8020: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c287fff8030: fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa
  0x0c287fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c287fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==22429==ABORTING

Error detected:

Code: Select all

... ERROR: AddressSanitizer: heap-use-after-free on address 0x614000000040 ...

Next is the stack trace information of the error location:

Code: Select all

...
    #0 0x555c1cd8b22c in main /tmp/test/prog/asan_demo/example_UseAfterFree.c:11
    #1 0x7f68ae183082 in __libc_start_main ../csu/libc-start.c:308
    #2 0x555c1cd8b10d in _start (/tmp/test/prog/asan_demo/example_UseAfterFree+0x110d)
...

Heap Buffer Overflow

Code: Select all

/**
 * $ gcc -fsanitize=address -fno-omit-frame-pointer -fsanitize-recover=address -g example_HeapOutOfBounds.c -o example_HeapOutOfBounds
 * $ ./example_HeapOutOfBounds
 */
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
    int *array = (int *)malloc(100 * sizeof(int));
    array[0] = 0;
    int res = array[100]; // BOOM
    free(array);
    return 0;
}

Code: Select all

=================================================================
==22873==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6140000001d0 at pc 0x55c246779288 bp 0x7ffcec56dff0 sp 0x7ffcec56dfe0
READ of size 4 at 0x6140000001d0 thread T0
    #0 0x55c246779287 in main /tmp/test/prog/asan_demo/example_HeapOutOfBounds.c:11
    #1 0x7f0c6bd3a082 in __libc_start_main ../csu/libc-start.c:308
    #2 0x55c24677912d in _start (/tmp/test/prog/asan_demo/example_HeapOutOfBounds+0x112d)

0x6140000001d0 is located 0 bytes to the right of 400-byte region [0x614000000040,0x6140000001d0)
allocated by thread T0 here:
    #0 0x7f0c6c015808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
    #1 0x55c246779205 in main /tmp/test/prog/asan_demo/example_HeapOutOfBounds.c:9
    #2 0x7f0c6bd3a082 in __libc_start_main ../csu/libc-start.c:308

SUMMARY: AddressSanitizer: heap-buffer-overflow /tmp/test/prog/asan_demo/example_HeapOutOfBounds.c:11 in main
Shadow bytes around the buggy address:
  0x0c287fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c287fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c287fff8000: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c287fff8010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c287fff8020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c287fff8030: 00 00 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa
  0x0c287fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c287fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c287fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c287fff8070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c287fff8080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==22873==ABORTING

Stack Buffer Overflow

Code: Select all

/**
 * $ gcc -fsanitize=address -fno-omit-frame-pointer -fsanitize-recover=address -g example_StackOutOfBounds.c -o example_StackOutOfBounds
 * $ ./example_StackOutOfBounds
 */
#include <stdio.h>

int main(int argc, char **argv) {
    int stack_array[100];
    stack_array[1] = 0;
    return stack_array[100]; // BOOM
}

Code: Select all

=================================================================
==23572==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd47c64410 at pc 0x558901e0931b bp 0x7ffd47c64230 sp 0x7ffd47c64220
READ of size 4 at 0x7ffd47c64410 thread T0
    #0 0x558901e0931a in main /tmp/test/prog/asan_demo/example_StackOutOfBounds.c:10
    #1 0x7f02e25d7082 in __libc_start_main ../csu/libc-start.c:308
    #2 0x558901e0912d in _start (/tmp/test/prog/asan_demo/example_StackOutOfBounds+0x112d)

Address 0x7ffd47c64410 is located in stack of thread T0 at offset 448 in frame
    #0 0x558901e091f8 in main /tmp/test/prog/asan_demo/example_StackOutOfBounds.c:7

  This frame has 1 object(s):
    [48, 448) 'stack_array' (line 8) <== Memory access at offset 448 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /tmp/test/prog/asan_demo/example_StackOutOfBounds.c:10 in main
Shadow bytes around the buggy address:
  0x100028f84830: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100028f84840: 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1 f1 f1
  0x100028f84850: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100028f84860: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100028f84870: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x100028f84880: 00 00[f3]f3 f3 f3 f3 f3 f3 f3 00 00 00 00 00 00
  0x100028f84890: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100028f848a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100028f848b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100028f848c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100028f848d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==23572==ABORTING

Global Buffer Overflow

Code: Select all

/**
 * $ gcc -fsanitize=address -fno-omit-frame-pointer -fsanitize-recover=address -g example_GlobalOutOfBounds.c -o example_GlobalOutOfBounds
 * $ ./example_GlobalOutOfBounds
 */
#include <stdio.h>

int global_array[100] = {-1};

int main(int argc, char **argv)
{
    return global_array[100];  // BOOM
}

Code: Select all

=================================================================
==24295==ERROR: AddressSanitizer: global-buffer-overflow on address 0x56444bf4c1b0 at pc 0x56444bf4920e bp 0x7ffe94aecd20 sp 0x7ffe94aecd10
READ of size 4 at 0x56444bf4c1b0 thread T0
    #0 0x56444bf4920d in main /tmp/test/prog/asan_demo/example_GlobalOutOfBounds.c:11
    #1 0x7f84d799b082 in __libc_start_main ../csu/libc-start.c:308
    #2 0x56444bf4910d in _start (/tmp/test/prog/asan_demo/example_GlobalOutOfBounds+0x110d)

0x56444bf4c1b0 is located 0 bytes to the right of global variable 'global_array' defined in 'example_GlobalOutOfBounds.c:7:5' (0x56444bf4c020) of size 400
SUMMARY: AddressSanitizer: global-buffer-overflow /tmp/test/prog/asan_demo/example_GlobalOutOfBounds.c:11 in main
Shadow bytes around the buggy address:
  0x0ac9097e17e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ac9097e17f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ac9097e1800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ac9097e1810: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ac9097e1820: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0ac9097e1830: 00 00 00 00 00 00[f9]f9 f9 f9 f9 f9 00 00 00 00
  0x0ac9097e1840: f9 f9 f9 f9 f9 f9 f9 f9 00 00 00 00 00 00 00 00
  0x0ac9097e1850: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ac9097e1860: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ac9097e1870: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ac9097e1880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==24295==ABORTING

Stack Use after Return

Code: Select all

/**
 * $ gcc -fsanitize=address -fno-omit-frame-pointer -fsanitize-recover=address -g example_UseAfterReturn.c -o example_UseAfterReturn
 * $ ASAN_OPTIONS=detect_stack_use_after_return=1 && ./example_UseAfterReturn
 */
#include <stdio.h>

int *p = NULL;

void foo(void)
{
    int local[100];
    p = &local[0];
}

int main(int argc, char **argv)
{
    foo();
    return p[0];
}

Code: Select all

=================================================================
==25711==ERROR: AddressSanitizer: stack-use-after-return on address 0x7f8a84f0a030 at pc 0x5578a77e03a4 bp 0x7ffddc5d4890 sp 0x7ffddc5d4880
READ of size 4 at 0x7f8a84f0a030 thread T0
    #0 0x5578a77e03a3 in main /tmp/test/prog/asan_demo/example_UseAfterReturn.c:18
    #1 0x7f8a88430082 in __libc_start_main ../csu/libc-start.c:308
    #2 0x5578a77e014d in _start (/tmp/test/prog/asan_demo/example_UseAfterReturn+0x114d)

Address 0x7f8a84f0a030 is located in stack of thread T0 at offset 48 in frame
    #0 0x5578a77e0218 in foo /tmp/test/prog/asan_demo/example_UseAfterReturn.c:10

  This frame has 1 object(s):
    [48, 448) 'local' (line 11) <== Memory access at offset 48 is inside this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-return /tmp/test/prog/asan_demo/example_UseAfterReturn.c:18 in main
Shadow bytes around the buggy address:
  0x0ff1d09d93b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ff1d09d93c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ff1d09d93d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ff1d09d93e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ff1d09d93f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0ff1d09d9400: f5 f5 f5 f5 f5 f5[f5]f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x0ff1d09d9410: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x0ff1d09d9420: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x0ff1d09d9430: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x0ff1d09d9440: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ff1d09d9450: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==25711==ABORTING

Note that it does not detect the error of stack-user-after-return. You need to set ASAN_OPTIONS=detect_stack_use_after_return=1 at runtime.

Stack Use After Scope

Code: Select all

/**
 * $ gcc -fsanitize=address -fno-omit-frame-pointer -fsanitize-recover=address -g example_UseAfterScope.c -o example_UseAfterScope
 * $ ./example_UseAfterScope
 */
#include <stdio.h>

volatile int *p = 0;

int main() {
  {
    int x = 0;
    p = &x;
  }
  *p = 5;
  return 0;
}

Code: Select all

=================================================================
==29749==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7ffc6c8de0b0 at pc 0x563079d0f320 bp 0x7ffc6c8de080 sp 0x7ffc6c8de070
WRITE of size 4 at 0x7ffc6c8de0b0 thread T0
    #0 0x563079d0f31f in main /tmp/test/prog/asan_demo/example_UseAfterScope.c:14
    #1 0x7fefabddd082 in __libc_start_main ../csu/libc-start.c:308
    #2 0x563079d0f14d in _start (/tmp/test/prog/asan_demo/example_UseAfterScope+0x114d)

Address 0x7ffc6c8de0b0 is located in stack of thread T0 at offset 32 in frame
    #0 0x563079d0f218 in main /tmp/test/prog/asan_demo/example_UseAfterScope.c:9

  This frame has 1 object(s):
    [32, 36) 'x' (line 11) <== Memory access at offset 32 is inside this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-scope /tmp/test/prog/asan_demo/example_UseAfterScope.c:14 in main
Shadow bytes around the buggy address:
  0x10000d913bc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000d913bd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000d913be0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000d913bf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000d913c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x10000d913c10: 00 00 f1 f1 f1 f1[f8]f3 f3 f3 00 00 00 00 00 00
  0x10000d913c20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000d913c30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000d913c40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000d913c50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000d913c60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==29749==ABORTING

Memory Leaks

Code: Select all

/**
 * $ gcc -fsanitize=address -fno-omit-frame-pointer -fsanitize-recover=address -g memory-leak.c -o memory-leak
 * $ ASAN_OPTIONS=detect_leaks=1 ./memory-leak
 */
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    char *p = malloc(7);
    p = 0; // The memory is leaked here.
    return 0;
}

Code: Select all

=================================================================
==30333==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 7 byte(s) in 1 object(s) allocated from:
    #0 0x7fa1e02c1808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
    #1 0x5616de82d1a5 in main /tmp/test/prog/asan_demo/memory-leak.c:10
    #2 0x7fa1dffe6082 in __libc_start_main ../csu/libc-start.c:308

SUMMARY: AddressSanitizer: 7 byte(s) leaked in 1 allocation(s).

Note that memory leak detection can be enabled by setting ASAN_OPTIONS=detect_leaks=1 at runtime.

Basic Principles

AddressSanitizer is a debugging tool based on shadow memory that detects memory errors. Its main working principle involves using special memory allocators and code injection to achieve its goal.

AddressSanitizer modifies the code at compile time so that it can detect memory errors at runtime. It checks the "shadow state" before each memory access and creates red zones to detect overflow and undefined behavior. The shadow state is a mapping mechanism that maps physical memory addresses to specific locations in virtual address space, allowing AddressSanitizer to track all memory operations. It divides the virtual address space into two parts: application memory and shadow memory. Application memory is the actual memory area used, while shadow memory is an additional memory area used to store information about whether each memory address is accessible.

When an application tries to access a memory address, AddressSanitizer checks the corresponding shadow byte value. If the value is zero, it indicates that the address is inaccessible; otherwise, AddressSanitizer continues executing the application code and records the memory access.

If the application attempts to access an inaccessible memory address, AddressSanitizer generates a crash report and stops the program execution. This helps developers identify and fix memory errors promptly.