部分文章内容为公开资料查询整理,原文出处可能未标注,如有侵权,请联系我,谢谢。邮箱地址:gnivor@163.com ►►►需要气球么?请点击我吧!

C++笔记-Asan(address-sanitize)的使用

参考资料

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

ASAN简介

AddressSanitizer(又名ASan)是C/C++的内存错误检测器。可以检测以下问题:
Use after free (dangling pointer dereference) - 释放后使用
Heap buffer overflow - 堆缓冲区溢出
Stack buffer overflow - 栈缓冲区溢出
Global buffer overflow - 全局缓冲区溢出
Use after return - return后使用
Use after scope - 作用域后使用
Initialization order bugs - 初始化顺序bug
Memory leaks - 内存泄露

ASAN使用

检查越界

测试代码
test_asan.cpp

#include <iostream>
int main() {
  int *arr = new int[10];
  int res = arr[10];  // index out of bounds
  std::cout << res << std::endl;
  delete[] arr;
  return 0;                                                                                                                                                             
}

编译

g++ -fsanitize=address test_string_split.cpp -g -o test

报错

/usr/bin/ld: cannot find /usr/lib64/libasan.so.4.0.0
collect2: error: ld returned 1 exit status

解决

sudo yum install /usr/lib64/libasan.so.4.0.0

执行test

./test

报错
7246ASan runtime does not come first in initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD.

需要将动态库加到LD_PRELOAD 一并执行test

LD_PRELOAD=/usr/lib64/libasan.so.4 ./test

结果

=================================================================
==12145==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x604000000038 at pc 0x000000400ba8 bp 0x7ffc1899b500 sp 0x7ffc1899b4f0
READ of size 4 at 0x604000000038 thread T0
    #0 0x400ba7 in main /data/xxx/test_cpp/test_asan.cpp:4
    #1 0x7fa6c5d09554 in __libc_start_main (/lib64/libc.so.6+0x22554)
    #2 0x400aa8  (/data/xxx/test_cpp/test+0x400aa8)

0x604000000038 is located 0 bytes to the right of 40-byte region [0x604000000010,0x604000000038)
allocated by thread T0 here:
    #0 0x7fa6c6a39968 in operator new[](unsigned long) (/usr/lib64/libasan.so.4+0xe0968)
    #1 0x400b68 in main /data/xxx/test_cpp/test_asan.cpp:3
    #2 0x7fa6c5d09554 in __libc_start_main (/lib64/libc.so.6+0x22554)

SUMMARY: AddressSanitizer: heap-buffer-overflow /datax/xxt/test_cpp/test_asan.cpp:4 in main
Shadow bytes around the buggy address:
  0x0c087fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c087fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c087fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c087fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c087fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c087fff8000: fa fa 00 00 00 00 00[fa]fa fa fa fa fa fa fa fa
  0x0c087fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff8050: 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
==12145==ABORTING

可见 heap-buffer-overflow 堆缓冲区溢出, 在main函数的第四行

检查内存泄露

test_asan2.cpp

#include <iostream>
int main() {
  int *ptr = new int(-1);
  std::cout << *ptr << std::endl;
  // delete ptr;                                                                                                                                                        
  return 0;
}
g++ -fsanitize=address test_asan2.cpp -g -o test
LD_PRELOAD=/usr/lib64/libasan.so.4 ./test

结果

=================================================================
==14998==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 4 byte(s) in 1 object(s) allocated from:
    #0 0x7f00df6ee7a8 in operator new(unsigned long) (/usr/lib64/libasan.so.4+0xe07a8)
    #1 0x400b78 in main /xxx/test_cpp/test_asan2.cpp:3
    #2 0x7f00de9be554 in __libc_start_main (/lib64/libc.so.6+0x22554)

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

可见第三行new了一个int指针,并未释放

bazel 编译时引入使用asan

项目结构

.
├── test
│   ├── BUILD
│   ├── test_asan2.cpp
│   └── test_asan.cpp
└── WORKSPACE

test_asan.cpp
test_asan2.cpp
内容与上文相同

// BUILD
package(default_visibility = ["//visibility:public"])                                                                                                                   
cc_binary(
    name = "test_asan",
    srcs = glob([
        "test_asan.cpp",
    ]), 
)
cc_binary(
    name = "test_asan2",
    srcs = glob([
        "test_asan2.cpp",
    ]), 
)

WORKSPACE为空

编译执行

bazel build ... -j 16 --compilation_mode=dbg --copt=-fsanitize=address --linkopt=-fsanitize=address
LD_PRELOAD=/usr/lib64/libasan.so.4 ./bazel-bin/test/test_asan
LD_PRELOAD=/usr/lib64/libasan.so.4 ./bazel-bin/test/test_asan2

或者也可以在WORKSPACE同级下面增加.bashrc文件

build --copt=-fsanitize=address
build --linkopt=-fsanitize=address

# 一些可用的编译选项
build --copt=-fno-omit-frame-pointer
build --copt=-fsanitize-recover=address
posted @ 2022-06-10 21:28  流了个火  阅读(5541)  评论(0编辑  收藏  举报
►►►需要气球么?请点击我吧!►►►
View My Stats