ASAN在CMake Debug配置下检测到内存泄漏,Release下未检测到,原因何在?
问题:Release构建下ASAN无法检测到内存泄漏?
我写了一个存在内存泄漏的C程序,通过CMake Debug配置构建并运行时,ASAN可正常检测到该泄漏;但切换至Release配置构建运行时,ASAN却显示无内存泄漏。使用CMake 3.8.x和3.9.x版本,基于C11测试,通过CLION或命令行指定CMAKE_BUILD_TYPE均出现相同现象。尝试修改编译选项、设置ASAN_OPTIONS和LSAN_OPTIONS后问题仍未解决。
main.cpp
#include <ios> #include <iostream> #include <fstream> #include <string> #include <chrono> using namespace std; using namespace std::chrono; int main(int argc, char **argv) { std::cout << "Hello, World!\n"; int *i = new int[10]; // 产生内存泄漏的代码 int j = rand()%9; std::cout<<"j="<<j<<std::endl; if(j<0||j>9) return 0; *(i+j) = 77; std::cout<<"i="<<*(i+j)<<std::endl; return 0; }
CMakeLists.txt
cmake_minimum_required(VERSION 3.1) project(leakTest) set(CMAKE_BUILD_RPATH "$ORIGIN") if (CMAKE_VERSION VERSION_LESS "3.1") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") else () set (CMAKE_CXX_STANDARD 11) endif () add_compile_options(-fsanitize=address) add_link_options(-fsanitize=address) add_executable(usingLeakTest main/src/main.cpp)
原因分析
编译器死代码消除优化:Release模式下默认开启
-O2级优化,编译器会分析代码逻辑,发现new int[10]分配的内存除了写入单个元素外,没有其他被依赖的场景(比如未将指针传递给外部函数、未读取数组其他元素,且程序退出后系统会自动回收进程内存),因此会直接消除这个堆分配操作——要么改用栈内存,要么完全跳过分配。既然内存根本没在堆上分配,ASAN自然检测不到泄漏。ASAN与Release优化的兼容性限制:尽管ASAN支持Release构建,但部分激进优化会破坏其内存跟踪机制。死代码消除就是典型案例,它会移除ASAN本应跟踪的内存分配指令,直接导致漏报。
验证与解决方法:
- 手动关闭死代码消除:在CMake中为Release模式添加编译选项
-fno-dead-code-elimination,比如修改CMakeLists.txt,添加set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-dead-code-elimination")。 - 修改代码让内存分配被视为必要操作:比如在main函数末尾添加
std::cout << "内存指针地址:" << i << std::endl;,让编译器认为指针i被实际使用,不会消除分配操作。
- 手动关闭死代码消除:在CMake中为Release模式添加编译选项
内容的提问来源于stack exchange,提问作者Imagron
相关产品推荐
相关产品推荐

