You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Clang AddressSanitizer编写精准抑制文件,解决gtest未测时的OpenSSL泄漏

解决AddressSanitizer误报OpenSSL静态库内存泄漏的精准抑制方案

问题背景

使用gtest_main驱动单元测试(已链接gtest_main库),执行无测试用例的命令(如./UnitTests --gtest_filter=NotExistingTest)时,AddressSanitizer(ASAN)会报告OpenSSL相关的间接内存泄漏(总泄漏量6213字节),导致程序退出码始终为1,干扰CI流程的结果判断。直接使用Clang提供的通用抑制规则(如interceptor_via_fun:CRYPTO_zalloc)会过度屏蔽,可能遗漏自身代码的真实内存泄漏,因此需要基于调用栈的精准抑制规则。涉及的OpenSSL版本为1.1.1g、3.0.4、3.0.8,均为自定义静态库构建。


方案一:编写精准栈级抑制规则

1. 生成完整泄漏调用栈

运行测试程序时,通过ASAN环境变量输出详细泄漏日志:

ASAN_OPTIONS=detect_leaks=1,log_path=asan_leak.log,leak_check_at_exit=1 ./UnitTests --gtest_filter=NotExistingTest

打开asan_leak.log,找到OpenSSL相关泄漏的完整调用栈(示例栈帧):

Direct leak of 128 bytes in 1 object allocated from:
    #0 0x7f9b12345678 in malloc (/lib64/libasan.so.5+0x108678)
    #1 0x7f9b11234567 in CRYPTO_zalloc crypto/mem.c:209
    #2 0x7f9b11234abc in OPENSSL_init_crypto crypto/init.c:456
    #3 0x7f9b11234def in openssl_init libcrypto.a(init.o)
    #4 0x7f9b10abcdef in __libc_start_main (/lib64/libc.so.6+0x27045)
    #5 0x55aabcdef123 in _start (/path/to/UnitTests+0x123)

2. 编写针对性抑制规则

创建抑制文件asan_openssl_suppressions.txt,针对上述栈帧编写规则(只匹配OpenSSL初始化阶段的泄漏,不影响业务代码的CRYPTO_zalloc调用):

leak:
  name: OpenSSL_Global_Init_Leak
  stack:
    - CRYPTO_zalloc
    - OPENSSL_init_crypto
    - openssl_init
    - __libc_start_main
    - _start

注意:不同OpenSSL版本的栈帧名称可能略有差异,需根据实际日志调整栈帧内容,确保只匹配无测试执行时触发的初始化泄漏。

3. 验证抑制效果

运行测试时指定抑制文件,确认OpenSSL泄漏不再被报告:

ASAN_OPTIONS=suppressions=asan_openssl_suppressions.txt ./UnitTests --gtest_filter=NotExistingTest

此时程序退出码应为0,且自身代码的内存泄漏仍会被ASAN正常检测。


方案二:手动清理OpenSSL全局资源(无需抑制)

如果不想依赖抑制文件,可通过自定义main函数替换gtest_main,在测试执行完成后手动调用OpenSSL的清理函数,释放初始化阶段分配的内存:

1. 编写自定义main函数

#include <gtest/gtest.h>
#include <openssl/crypto.h>

int main(int argc, char** argv) {
    testing::InitGoogleTest(&argc, argv);
    int test_result = RUN_ALL_TESTS();
    
    // 清理OpenSSL全局资源,适配1.1.1+版本
    OPENSSL_cleanup();
    // 针对旧版本可补充调用:CRYPTO_cleanup_all_ex_data();
    
    return test_result;
}

2. 编译链接调整

编译时不再链接gtest_main库,改为链接gtest库,确保自定义main函数被执行:

# 原配置:target_link_libraries(UnitTests gtest_main)
target_link_libraries(UnitTests gtest)

此方案通过主动释放OpenSSL初始化内存,从根源消除ASAN的泄漏报告,同时不影响测试用例中的OpenSSL使用(清理操作在RUN_ALL_TESTS()之后执行)。


CI流程适配

在CI脚本中添加ASAN环境变量配置,确保抑制规则或清理逻辑生效:

# 使用抑制方案时:
export ASAN_OPTIONS="suppressions=asan_openssl_suppressions.txt:detect_leaks=1"
./UnitTests --gtest_filter=$TEST_FILTER

# 使用自定义main方案时,直接运行即可:
./UnitTests --gtest_filter=$TEST_FILTER

这样既保证OpenSSL的误报泄漏被处理,又能让ASAN正常检测自身代码的真实泄漏,确保CI流程能通过退出码判断测试结果。


内容的提问来源于stack exchange,提问作者Marek R

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 10:50:32