ASan(AddressSanitizer):Google的C/C++内存地址错误检查器

Address Sanitizer是google的C/C++内存地址错误检查器。其在编译时和运行时发挥作用,已被集成进了各大编译器之中。

一、它可以检测出下面这些错误

1. Use after free (dangling pointer dereference):使用已释放的堆内存

// RUN: clang -O -g -fsanitize=address %t && ./a.out
int main(int argc, char **argv) {
  int *array = new int[100];
  delete [] array;
  return array[argc];  // BOOM
}

2. Heap buffer overflow:堆内存溢出

// RUN: clang -O -g -fsanitize=address %t && ./a.out
int main(int argc, char **argv) {
  int *array = new int[100];
  array[0] = 0;
  int res = array[argc + 100];  // BOOM
  delete [] array;
  return res;
}

3. Stack buffer overflow:栈内存溢出

// RUN: clang -O -g -fsanitize=address %t && ./a.out
int main(int argc, char **argv) {
  int stack_array[100];
  stack_array[1] = 0;
  return stack_array[argc + 100];  // BOOM
}

4. Global buffer overflow:访问的区域是全局变量, 并且超过了分配给它的空间

// RUN: clang -O -g -fsanitize=address %t && ./a.out
int global_array[100] = {-1};
int main(int argc, char **argv) {
  return global_array[argc + 100];  // BOOM
}

5. Use after return:默认不开启, 指: 函数在栈上的局部变量在函数返回后被使用

// RUN: clang -O -g -fsanitize=address %t && ./a.out
// By default, AddressSanitizer does not try to detect
// stack-use-after-return bugs.
// It may still find such bugs occasionally
// and report them as a hard-to-explain stack-buffer-overflow.

// You need to run the test with ASAN_OPTIONS=detect_stack_use_after_return=1

int *ptr;
__attribute__((noinline))
void FunctionThatEscapesLocalObject() {
  int local[100];
  ptr = &local[0];
}

int main(int argc, char **argv) {
  FunctionThatEscapesLocalObject();
  return ptr[argc];
}

6. Use after scope:使用作用域之外的变量

// RUN: clang -O -g -fsanitize=address -fsanitize-address-use-after-scope \
//    use-after-scope.cpp -o /tmp/use-after-scope
// RUN: /tmp/use-after-scope

// Check can be disabled in run-time:
// RUN: ASAN_OPTIONS=detect_stack_use_after_scope=0 /tmp/use-after-scope

volatile int *p = 0;

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

7. Initialization order bugs:默认不开启,检查全局变量或静态变量初始化的时候有没有利用未初始化的变量

$ cat tmp/init-order/example/a.cc
#include <stdio.h>
extern int extern_global;
int __attribute__((noinline)) read_extern_global() {
  return extern_global;
}
int x = read_extern_global() + 1;
int main() {
  printf("%d\n", x);
  return 0;
}

$ cat tmp/init-order/example/b.cc
int foo() { return 42; }
int extern_global = foo();

8. Memory leaks:内存泄漏,检查未释放的堆内存

$ cat memory-leak.c 
#include <stdlib.h>

void *p;

int main() {
  p = malloc(7);
  p = 0; // The memory is leaked here.
  return 0;
}
$ clang -fsanitize=address -g memory-leak.c
$ ./a.out 

二、使用

ASAN的使用需编译器支持。GCC、clang最简单的使用方式是增加编译选项:-fsanitize=address。更多选项可以看官方文档:

clang的使用方式:

AddressSanitizer — Clang 16.0.0git documentation

GCC的使用方式:

Instrumentation Options (Using the GNU Compiler Collection (GCC))

 

三、原理简介

首先我们需要接管每次内存分配/释放. 并且每一次对内存的读/写都需要加上一个检查 (所以需要编译器的配合).

对于上面这些需要检测出的问题, ASan 提出了解决方案, 可以比较好的处理这些问题, 同时不至于损失太多性能/空间.

参考资料:

1. AddressSanitizer · google/sanitizers Wiki · GitHub

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值