ASAN 内存泄漏检测

简介

Sanitizer 项目是谷歌出品的一个开源项目,提供直接使用现有构建系统和现有测试资产的运行时错误查找技术。该项目包含了 ASAN(内存错误检测工具)、LSAN(内存泄漏检测工具)、MSAN(未初始化内存读取的检测工具)、TSAN(线程间数据竞争的检测工具)等内存、线程错误的检测工具。 ASAN全称 AddressSanitizer,可以用来检测内存问题,例如缓冲区溢出或对悬空指针的非法访问等。

根据谷歌的工程师介绍 ASAN 已经在 chromium 项目上检测出了300多个潜在的未知bug,而且在使用 ASAN 作为内存错误检测工具对程序性能损耗也是及其可观的。根据检测结果显示可能导致性能降低2倍左右,比Valgrind(官方给的数据大概是降低10-50倍)快了一个数量级。

从LLVM3.1、GCC4.8、XCode7.0、MSVC16.9开始ASAN就已经成为众多主流编译器的内置工具了,因此,要在项目中使用ASAN也是十分方便。现在只需要在编译命令中加上-fsanitize=address检测选项就可以让ASAN在你的项目中大展神通。

原理:

内存泄漏的检测原理,基本上都是通过 hook malloc free 等内存分配函数实现,asan 同样也是如此。详细介绍 : https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm

使用方式:

使用 ASAN 的方式很简单,因为编译器已经将 ASAN 作为内置工具,对于手动使用 gcc 构建的工程,使用非常简单,只需要在编译的时候添加-fsanitize=address编译选项即可。对于 cmake , configure 等构建工程的使用方式稍微麻烦一点,我已经总结出来放在文档最后。

实战分析:

当编译目标程序编译完成之后,运行目标程序即可。程序退出后,检测日志输出到标准输出。下面使用简单的示例说明:

源码如下:

Main.c

int main()

{

      char* s = new char[256];

return 0;

}

编译:

g++ -fsanitize=address -g main.cpp -o main

运行:

$ export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.5

$ ./main

=================================================================

==2499561==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 256 byte(s) in 1 object(s) allocated from:

    #0 0x7fadbeb0f787 in operator new[](unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cc:107

    #1 0x56386698619e in main /root/memoryLeakTest/main.cpp:3

    #2 0x7fadbe4e6082 in __libc_start_main ../csu/libc-start.c:308

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

Direct leak of 256 byte(s) in 1 object(s) allocated from 表示 有256 byte 的内存为 直接泄漏。下面为导致该泄漏的调用堆栈。

除了上述的直接泄漏,还会下图这样的间接泄漏,Indirect leak 表示泄漏是不确定的,可能是误报,需要结合代码进行分析。

总之 asan 对于内存泄漏的检测还是很全面。不管是直接泄漏,还是间接泄漏都是需要我们注意的。Asan 除了内存泄漏的检测,还有开头介绍的一些其他内存错误的检测工具,可以帮助我们是自己的程序更加健壮,感兴趣的可以自行研究。

其他工程使用方式

  1. 使用 gcc 命令直接编译

gcc example.c -o -fsanitize=address -g

  1. 使用 cmake 构建的工程

直接在 CMakelists.txt 中添加以下代码:

set(CMAKE_CXX_FLAGS "-fsanitize=undefined,address,leak -fno-omit-frame-pointer")

set(CMAKE_C_FLAGS "-fsanitize=undefined,address,leak -fno-omit-frame-pointer")

set(CMAKE_L_FLAGS "-fsanitize=undefined,address,leak -fno-omit-frame-pointer")

  1. 使用 qmake 构建的工程

和上述 cmake一样,直接在 pro 工程中添加以下代码即可:

QMAKE_CXXFLAGS += -fsanitize=undefined,address,leak -fno-omit-frame-pointer

QMAKE_CFLAGS  += -fsanitize=undefined,address,leak -fno-omit-frame-pointer

QCMAKE_LFLAGS += -fsanitize=undefined,address,leak -fno-omit-frame-pointer

  1. 使用 CMake 构建的工程

set(CMAKE_CXX_FLAGS "-fsanitize=undefined,address,leak -fno-omit-frame-pointer")

set(CMAKE_C_FLAGS "-fsanitize=undefined,address,leak -fno-omit-frame-pointer")

set(CMAKE_L_FLAGS "-fsanitize=undefined,address,leak -fno-omit-frame-pointer")

  1. 使用 configure 构建的工程

./configure CPPFLAGS= “ -fsanitize=undefined,address,leak -fno-omit-frame-pointer” CFLAGS=” -fsanitize=undefined,address,leak -fno-omit-frame-pointer” LDFLAGS=” -fsanitize=undefined,address,leak -fno-omit-frame-pointer”

  1. 使用 meson 构建的工程

meson -Db_sanitize=address

  1. Deb 包构建

如果需要构建 带有 ASAN 的 deb 包,设置以下环境变量,再通过构建命令构建deb 即可

export DEB_CXXFLAGS_SET="-fsanitize=undefined,address,leak -fno-omit-frame-pointer"

export DEB_CFLAGS_SET="-fsanitize=undefined,address,leak -fno-omit-frame-pointer"

export DEB_LDFLAGS_SET="-fsanitize=undefined,address,leak -fno-omit-frame-pointer"

参考文献:

Asan 项目wiki:  https://github.com/google/sanitizers/wiki/AddressSanitizer

Microsoft Asan 介绍:AddressSanitizer | Microsoft Learn

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值