【分享】内存错误分析 - AddressSanitizer
C/C++ 通常作为嵌入式开发的首选编程语言,在开发过程中,碰到内存错误是很常见的。内存错误是非常致命的问题,一旦发生通常会引起程序奔溃,并且排查起来极其困难。
幸运的是,我们可以借助一些工具来检测此类错误,使用编译工具链内置的 AddressSanitize
功能是最佳的解决方案。
简介
AddressSanitizer(简称 ASan)是一种内存错误检测器,主要用于 C/C++ 程序。它可以在运行时检测出诸如缓冲区溢出、使用未初始化的内存、使用已释放的内存等常见内存错误。从 GCC 4.8 开始,AddressSanitizer 成为 GCC 的一部分。通过使用 AddressSanitizer,我们可以在开发过程中及时发现并修复这些内存错误的问题,从而提高软件的稳定性和安全性。
基本使用
由于编译工具内置了 AddressSanitizer,所以使用上非常方便,只需要在编译时添加特定的编译选项就可以启用 AddressSanitizer。
编译程序的时候,添加 -fsanitize=address
和 -fno-omit-frame-pointer
编译选项即可。示例:
Code: Select all
$ gcc -fsanitize=address -fno-omit-frame-pointer -g -o my_program my_program.c
把编译好的程序放到板子上运行,如果程序中存在内存错误,AddressSanitizer 将在检测到错误时终止程序,并输出详细的错误信息,我们可以根据这些信息来定位问题。
注意,AddressSanitizer 依赖 libasan 运行库,如果板子上的固件没有包含该库,需要从交叉编译工具链里面查找,把工具链中的动态库上传到板子上。
访问释放的内存
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
检测到错误:
Code: Select all
... ERROR: AddressSanitizer: heap-use-after-free on address 0x614000000040 ...
紧接着是发生错误地方的栈回溯信息:
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)
...
堆溢出
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
栈溢出
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
全局缓冲区溢出
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
返回后使用堆栈内存
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
注意,默认是不检测返回后使用栈内存,需要在运行时设置环境变量 ASAN_OPTIONS=detect_stack_use_after_return=1。
使用超出范围的堆栈内存
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
内存泄露
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).
注意,可以在运行时设置环境变量 ASAN_OPTIONS=detect_leaks=1 开启内存泄露检测。
基本原理
AddressSanitizer 是一种基于阴影内存(shadow memory)的调试工具,用于检测内存错误。它的主要工作原理是通过使用特殊的内存分配器和代码注入来实现。
AddressSanitizer 在编译时对代码进行修改,以便在运行时能够检测到内存错误。它会在每个内存访问之前检查“影子状态”(shadow state),并创建红色区域(red zones)来检测溢出和未定义行为。影子状态是一种映射机制,它可以将物理内存地址映射到虚拟地址空间中的特定位置,从而使得 AddressSanitizer 能够跟踪所有内存操作。它将虚拟地址空间分成两部分:应用程序内存和阴影内存。应用程序内存是实际使用的内存区域,而阴影内存则是附加的内存区域,用于存储每个内存地址是否可访问的信息。
当应用程序尝试访问某个内存地址时,AddressSanitizer 会检查该地址对应的阴影字节值。如果该值为零,则表示该地址不可访问;否则,AddressSanitizer 将继续执行应用程序代码并记录该内存访问。
如果应用程序试图访问不可访问的内存地址,AddressSanitizer 将生成一个崩溃报告,并停止程序运行。这有助于开发人员及时发现和修复内存错误。