AddressSanitizer (ASan) 是查找c++程序错误的神器。它是一种编译器和运行时技术,它公开了许多误报率为零的难以发现的 bug:

从 Visual Studio 2019 版本 16.9 开始,Microsoft C/C++ 编译器 (MSVC) 和 IDE 支持AddressSanitizer清理器。关于AddressSanitizer的详细介绍请查看微软官方对它的介绍https://learn.microsoft.com/zh-cn/cpp/sanitizers/asan?view=msvc-170

配置条件:win11系统, clion c++语言,msvc工具链,debug模式

cmakelists.txt设置如下:

cmake_minimum_required(VERSION 4.0)
project(AddressSanitizer_test)

set(CMAKE_CXX_STANDARD 20)

add_executable(test main.cpp)


# 启用AddressSanitizer
target_compile_options(test PRIVATE -fsanitize=address)
# 建议同时添加以下标志以获得更清晰的堆栈跟踪信息:cite[4]:cite[8]
# target_compile_options(test PRIVATE -fno-omit-frame-pointer -O1)

# 链接AddressSanitizer所需的库:cite[1]:cite[2]
target_link_directories(test PRIVATE
        "H:/Visual_Studio_2022/VC/Tools/MSVC/14.43.34808/bin/Hostx64/x64"
        "H:/Visual_Studio_2022/VC/Tools/MSVC/14.43.34808/lib/x64"
)
target_link_libraries(test PRIVATE
        clang_rt.asan_dynamic-x86_64
        clang_rt.asan_dynamic_runtime_thunk-x86_64)
target_link_options(test PRIVATE
        /wholearchive:clang_rt.asan_dynamic_runtime_thunk-x86_64.lib)

测试代码

#include <iostream>

int main() {
    // 动态分配一个整数数组
    int *array = new int[10];

    // 故意在数组边界外写入,触发堆缓冲区溢出
    array[10] = 123;  // 错误:有效索引为0-9,10是越界访问

    // 释放内存
    delete[] array;

    return 0;
}

运行后AddressSanitizer给出的报告:

=================================================================
==13260==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x1270e9ca04f8 at pc 0x7ff6094f10df bp 0x006fff14fc50 sp 0x006fff14fc58
WRITE of size 4 at 0x1270e9ca04f8 thread T0
    #0 0x7ff6094f10de in main E:\coding\cppcode\AddressSanitizer_test\main.cpp:8
    #1 0x7ff6094f2a78 in invoke_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
    #2 0x7ff6094f29c1 in __scrt_common_main_seh D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
    #3 0x7ff6094f287d in __scrt_common_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:330
    #4 0x7ff6094f2aed in mainCRTStartup D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_main.cpp:16
    #5 0x7ffb420a259c  (C:\Windows\System32\KERNEL32.DLL+0x18001259c)
    #6 0x7ffb42d4af37  (C:\Windows\SYSTEM32\ntdll.dll+0x18005af37)

0x1270e9ca04f8 is located 0 bytes after 40-byte region [0x1270e9ca04d0,0x1270e9ca04f8)
allocated by thread T0 here:
    #0 0x7ff6094f1c5e in operator new[](unsigned __int64) D:\a\_work\1\s\src\vctools\asan\llvm\compiler-rt\lib\asan\asan_win_new_array_thunk.cpp:41
    #1 0x7ff6094f1079 in main E:\coding\cppcode\AddressSanitizer_test\main.cpp:5
    #2 0x7ff6094f2a78 in invoke_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
    #3 0x7ff6094f29c1 in __scrt_common_main_seh D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
    #4 0x7ff6094f287d in __scrt_common_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:330
    #5 0x7ff6094f2aed in mainCRTStartup D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_main.cpp:16
    #6 0x7ffb420a259c  (C:\Windows\System32\KERNEL32.DLL+0x18001259c)
    #7 0x7ffb42d4af37  (C:\Windows\SYSTEM32\ntdll.dll+0x18005af37)

SUMMARY: AddressSanitizer: heap-buffer-overflow E:\coding\cppcode\AddressSanitizer_test\main.cpp:8 in main
Shadow bytes around the buggy address:
  0x1270e9ca0200: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 07 fa
  0x1270e9ca0280: fa fa 00 00 00 00 00 01 fa fa 00 00 00 00 00 04
  0x1270e9ca0300: fa fa 00 00 00 00 00 02 fa fa 00 00 00 00 01 fa
  0x1270e9ca0380: fa fa 00 00 00 00 07 fa fa fa 00 00 00 00 00 01
  0x1270e9ca0400: fa fa 00 00 00 00 07 fa fa fa 00 00 00 00 07 fa
=>0x1270e9ca0480: fa fa 00 00 00 00 06 fa fa fa 00 00 00 00 00[fa]
  0x1270e9ca0500: fa fa 00 00 00 00 00 fa fa fa fa fa fa fa fa fa
  0x1270e9ca0580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1270e9ca0600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1270e9ca0680: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1270e9ca0700: 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
==13260==ABORTING

Process finished with exit code 1

从这个报告可以看出是什么错误引起的:

==1088==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x113177ba04f8 at pc 0x7ff7d49f10df bp 0x0018dadbfc20 sp 0x0018dadbfc28 WRITE of size 4 at 0x113177ba04f8 thread T0

  • 错误类型heap-buffer-overflow - 堆缓冲区溢出,即访问了堆上分配的缓冲区的边界之外的内存

  • 进程ID: 1088

  • 内存地址0x113177ba04f8 - 发生溢出的具体内存地址

  • 操作WRITE of size 4 - 进行了4字节的写入操作(对应int类型)

  • 线程: T0 (主线程)

调用堆栈跟踪

#0 0x7ff7d49f10de in main E:\coding\cppcode\AddressSanitizer_test\main.cpp:8

关键信息: 错误发生在你的代码 main.cpp 第8行。在你的测试代码中,这对应:

arr[10] = 42; // 第8行 - 堆缓冲区溢出

其他堆栈帧 (#1-#7) 是C++运行时和Windows系统的启动代码,对于调试来说不太重要。

......

这个报告展示了AddressSanitizer强大的诊断能力 - 它不仅告诉你发生了错误,还精确指出了错误的位置、内存分配的历史以及内存布局的详细信息。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐