asan内存检测工具的原理和使用

Hello,各位看官好,小弟的公司最近开始使用asan这个工具了,最近在晚上查了一下,不查不知道,一查吓一跳,这个工具真的是神一般的工具,所以我就花了一点时间整理了一下asan工具的用法。

一、asan是什么?

ASAN(全称为AddressSanitizer),是一种比valgrind更为强大的检测工具,通过这个工具,我们可以轻松检测出内存的问题并且可以初步将问题进行分类,比如堆溢出,栈溢出等等。

二、和其他检测工具相比较

最有名的检测工具就是valgrind工具,但是这个工具有一个大问题就是运行时候占用的内存过大,从而导致程序运行过慢,而asan完美的解决了这个问题,它大概只会在原有程序基础上拖慢1倍,而valgrind则会拖慢30~50倍。

三、asan工具的使用前提

  1. asan的使用前提必须要在gcc或者g++4.8以上的编译器中,当然这个因为楼主所使用的编译器默认为5.4,因此不存在这种问题。

  2. asan中一定要有libasan.so.3这个库,如果没有是不行的。

  3. 编译选项中需要添加两个编译选项,其一是(-fsanitize=address)这个选项添加的原因是将asan添加进入编译中,其二是添加-g,这个就是增加堆栈信息,只有这样才能看出函数名称。

  4. 在asan工具中,我们还可以设置一些编译选项,比如

  • ASAN_OPTIONS是Address-Sanitizier的运行选项环境变量。
# halt_on_error=0:检测内存错误后继续运行

# detect_leaks=1:使能内存泄露检测

# malloc_context_size=15:内存错误发生时,显示的调用栈层数为15

# log_path=/home/xos/asan.log:内存检查问题日志存放文件路径

# suppressions=$SUPP_FILE:屏蔽打印某些内存错误
  • 除了上述常用选项,以下还有一些选项可根据实际需要添加:
# detect_stack_use_after_return=1:检查访问指向已被释放的栈空间

# handle_segv=1:处理段错误;也可以添加handle_sigill=1处理SIGILL信号

# quarantine_size=4194304:内存cache可缓存free内存大小4M

四、asan能够检测出的内存问题

  1. use after free(free之后继续使用)

  2. Heap after overflow(堆溢出)

  3. stack after overflow(栈溢出)

  4. global after overflow(全局变量溢出)

  5. use after return(返回之后继续使用)

  6. use after scope(超过作用域)

  7. Initialization order bugs(初始化顺序bug)

  8. Memory leaks(内存泄漏)

五、asan使用原理

  1. 看了一些asan的使用原理,其实也还比较简单,他的核心算法有两点,其一就是就是在他的周边添加监控内存,其二就是映射,这样在使用的时候只要检测到是否踏入周边内存就可以知道是否报错

六、代码解析

// 测试全局溢出
void testBuffer()
{
    globalBuffer[100] = 10;
    return;
}

void heapOverFlow()
{
    char *heap_buf = (char *)malloc(sizeof(char) * 32);
    memcpy(heap_buf + 30, "overflow", 8);
    free(heap_buf);
    return;
}

void vectorheapOverFlow()
{
    vector<int> test;
    test.push_back(0);
    test.push_back(0);
    test[10] = 0;
    return;
}

void stackOverFlow()
{
    char test[4];
    test[4] = 0;
}

void wildPointerOverFlow()
{
    char *p = (char *)malloc(30);
    free(p);
    if (p == NULL)
    {
        std::cout<<"p is NULL"<<std::endl;
    }
    else if (p == nullptr)
    {
        std::cout<<"p is nullptr"<<std::endl;
    }
    else
    {
        std::cout<<"p is true"<<std::endl;
    }

    int a = p[1];
    return;
}

void wildPointerAnotherFlow()
{
    int *p = new int;
    delete p;
    std::cout<<"p is 11111:"<<p<<std::endl;
    long *p1 = new long;
    std::cout<<"p1 is 22222:"<<p1<<std::endl;
    *p1 = 100;
    std::cout<<"p1 is 33333:"<<*p1<<std::endl;
    *p = 23;
    std::cout<<"p1 is 44444:"<<*p1<<std::endl;
    std::cout<<"p is 555555:"<<*p<<std::endl;
    return;
}

void doubleFree()
{
    char *p = (char *)malloc(10);
    free(p);
    free(p);
    return;
}


void exitScope()
{
    int *p;
    {
        int num = 10;
        p =&num;
    }

    std::cout<<"p is:"<<*p<<std::endl;
}

char * memoryleak()
{
    char *str = (char *)malloc(32);
    strcpy(str,"overflow");
    return str;
}

int main(int argc, char *argv[])
{
    // 测试全局buffer
    // testBuffer();
    // 测试堆缓冲区溢出
    // heapOverFlow();
    // vectorheapOverFlow();
    // 测试栈缓冲区溢出
    // stackOverFlow();
    // 测试野指针
    // wildPointerOverFlow();
    // wildPointerAnotherFlow();
    // double-free
    // doubleFree();
    // 退出作用閾
    // exitScope();
    // 内存泄漏
    char *str = memoryleak();
    // free(str);
    return 0;
}

以上都是一些作用案例,这些可以给大家参考

七、参考资料

https://github.com/google/sanitizers/wiki/AddressSanitizer
PS:补充一下,由于这个博客园没有上传附件的功能,所以libasan.so.1就不能上传了,请大家自行下载。

猜你喜欢

转载自blog.csdn.net/qq_39825430/article/details/128838947