内存问题检查工具——Address Sanitizer(ASAN)

内存问题检查工具——Address Sanitizer(ASAN)

Address Sanitizer(ASAN)是gcc自带的内存问题检查工具,比较轻量级,非常适合单元测试时检查内存问题。使用也比较简单,只需要在编译时候加“-fsanitize=address -fno-omit-frame-pointer” 即可。若想更精确查看到源码位置,可以加 “-g” 编译debug版本。下面给出几个简单案例。

案例一:内存泄漏

#include<stdio.h>
#include<stdlib.h>

int main() {
    void* buf = malloc(1024);
    return 0;
}

编译:“gcc hello.c -fsanitize=address -fno-omit-frame-pointer -g” ,然后直接执行 ./a.out 即可:

=================================================================
==3440094==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 1024 byte(s) in 1 object(s) allocated from:
    #0 0x7f1530026808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
    #1 0x55c8c0e8119e in main /home/loongknown/test/hello.c:5
    #2 0x7f152fd4b082 in __libc_start_main ../csu/libc-start.c:308

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

案例二:读越界

#include<stdio.h>
#include<stdlib.h>

int main() {
    int a[10] = {0};
    int x = a[10];
    return 0;
}

编译和执行同上:

=================================================================
==3440706==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffcdc0fdf68 at pc 0x55c54dad2352 bp 0x7ffcdc0fdef0 sp 0x7ffcdc0fdee0
READ of size 4 at 0x7ffcdc0fdf68 thread T0
    #0 0x55c54dad2351 in main /home/loongknown/test/hello.c:6
    #1 0x7f70259e6082 in __libc_start_main ../csu/libc-start.c:308
    #2 0x55c54dad212d in _start (/home/loongknown/test/a.out+0x112d)

Address 0x7ffcdc0fdf68 is located in stack of thread T0 at offset 88 in frame
    #0 0x55c54dad21f8 in main /home/loongknown/test/hello.c:4

  This frame has 1 object(s):
    [48, 88) 'a' (line 5) <== Memory access at offset 88 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 /home/loongknown/test/hello.c:6 in main
Shadow bytes around the buggy address:
  0x10001b817b90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001b817ba0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001b817bb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001b817bc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001b817bd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x10001b817be0: 00 00 f1 f1 f1 f1 f1 f1 00 00 00 00 00[f3]f3 f3
  0x10001b817bf0: f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001b817c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001b817c10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001b817c20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001b817c30: 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
==3440706==ABORTING

越界源码位置和越界的地址都有清晰的显示。

案例三:写越界

#include<stdio.h>
#include<stdlib.h>

int main() {
    int a[10] = {0};
    a[10] = 1;
    return 0;
}

同上编译和执行:

=================================================================
==3441478==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd938896e8 at pc 0x55e6f9bc8352 bp 0x7ffd93889680 sp 0x7ffd93889670
WRITE of size 4 at 0x7ffd938896e8 thread T0
    #0 0x55e6f9bc8351 in main /home/loongknown/test/hello.c:6
    #1 0x7fd974ba6082 in __libc_start_main ../csu/libc-start.c:308
    #2 0x55e6f9bc812d in _start (/home/loongknown/test/a.out+0x112d)

Address 0x7ffd938896e8 is located in stack of thread T0 at offset 88 in frame
    #0 0x55e6f9bc81f8 in main /home/loongknown/test/hello.c:4

  This frame has 1 object(s):
    [48, 88) 'a' (line 5) <== Memory access at offset 88 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 /home/loongknown/test/hello.c:6 in main
Shadow bytes around the buggy address:
  0x100032709280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100032709290: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000327092a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000327092b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000327092c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x1000327092d0: 00 00 f1 f1 f1 f1 f1 f1 00 00 00 00 00[f3]f3 f3
  0x1000327092e0: f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000327092f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100032709300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100032709310: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100032709320: 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
==3441478==ABORTING

推荐大家尝试使用!本文结束。

  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以使用AddressSanitizer检查全局二维数组。AddressSanitizer是一个内存错误检测工具,可以在运行时发现内存错误,包括使用未初始化的内存、使用已释放的内存、缓冲区溢出等等。以下是一个示例程序,演示如何使用AddressSanitizer检查全局二维数组。 ```c++ #include <iostream> #include <cstring> #include <cstdlib> // 定义一个全局的二维数组 int arr[10][10]; int main() { // 对数组进行访问 for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { arr[i][j] = i * j; } } // 使用 AddressSanitizer 进行检查 std::memset(arr, 0, sizeof(arr)); // 将数组初始化为0,以便检查未初始化内存 std::cout << "Enter array index to access: "; int i, j; std::cin >> i >> j; std::cout << "arr[" << i << "][" << j << "] = " << arr[i][j] << std::endl; return 0; } ``` 编译时需要使用-fsanitize=address选项启用AddressSanitizer,例如: ``` g++ -fsanitize=address -o test test.cpp ``` 运行时会输出类似以下的信息,提示存在访问未初始化内存的错误: ``` AddressSanitizer:DEADLYSIGNAL ================================================================= ==1==ERROR: AddressSanitizer: global-buffer-overflow on address 0x00010f5b3f80 at pc 0x7f72e1f4c0b6 bp 0x7ffc4132b330 sp 0x7ffc4132b328 READ of size 4 at 0x00010f5b3f80 thread T0 #0 0x7f72e1f4c0b5 in main (/path/to/test+0x10b5) #1 0x7f72e1c59b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96) #2 0x7f72e1f4b3ed in _start (/path/to/test+0xb3ed) Address 0x00010f5b3f80 is a global variable located at offset 0 in segment of size 8000 in arena "global" ``` 可以根据这个信息,定位代码中的错误,并进行修复。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值