openssl3.2 - crypto-mdebug被弃用后, 内存泄漏检查的替代方法
文章目录
openssl3.2 - crypto-mdebug被弃用后, 内存泄漏检查的替代方法
概述
调用openssl接口后, 如果用到了openssl对象, 需要释放, 否则会发生内存泄漏.
即使不是新手, 也不能保证释放函数都调用了. 想想我们自己写程序, new后, 没有delete的情况就知道, 可以理解.
谁能保证自己手搓的应用实现100%没内存泄漏呢?
看资料时, 发现openssl本身有这个检查库本身发生内存泄漏的特性, 大概就是申请内存时, openssl自己记录了一下, free内存时, 将对应记录删掉.
这样, 在程序退出前, 再调用一下内存分配记录列表接口, 就知道哪里的内存没释放.
那试试, 加入crypto-mdebug特性, 模拟一下内存泄漏(调用openssl_new(), 不调用openssl_free()), 看看啥效果.
笔记
查看特性列表
perl configdata.pm --dump > my_log.txt
查看my_log.txt, 就有openssl 特性列表.
有启用的特性列表, 也有被禁掉的特性列表.
如果要加入特性, 就看禁止列表中的特性.
怎么打开crypto-mdebug特性呢?
看Configure可知, 只要带上参数 enable-crypto-mdebug即可.
结合我最后实验可用的编译脚本, 加入 enable-crypto-mdebug
openssl3.2编译脚本 - 加入enable-crypto-mdebug
解开官方源码包
打开vs2019x64本地命令行, 选择管理员身份运行
cd /d D:\3rd_prj\crypt\openssl-3.2.0
set path=c:\nasm;%path%
perl Configure VC-WIN64A --debug enable-crypto-mdebug zlib-dynamic --with-zlib-include=D:\my_dev\lib\zlib_1d3 --with-zlib-lib=.\my_zlib_1d3.dll --prefix=c:\openssl_3d2 --openssldir=c:\openssl_3d2\common
nmake
手工拷贝, 将 my_zlib_1d3.dll 拷贝到以下4个目录
.\
.\apps
.\fuzz
.\test
nmake test
nmake install
手工拷贝
D:\my_dev\lib\zlib_1d3\my_zlib_1d3.dll => C:\openssl_3d2\bin\my_zlib_1d3.dll
归档
C:\openssl_3d2 剪切到自己的库目录 => D:\my_dev\lib\openssl_3d2
写个测试程序, 调用一下内存泄漏检查的相关接口, 看看能否编译过, 然后试试接口怎么用.
/*!
* \file main.cpp
*/
#include "my_openSSL_lib.h"
#include <openssl/crypto.h> // for mem leak API
int main(int argc, char** argv)
{
CRYPTO_mem_leaks(NULL);
return 0;
}
/*!
编译错误
已启动重新生成…
1>------ 已启动全部重新生成: 项目: prj_template, 配置: Debug x64 ------
1>main.cpp
1>D:\my_dev\my_local_git_prj\study\openSSL\exp\call_mem_leak_API\main.cpp(12,2): error C4996: 'CRYPTO_mem_leaks': Since OpenSSL 3.0
1>已完成生成项目“prj_template.vcxproj”的操作 - 失败。
========== 全部重新生成: 成功 0 个,失败 1 个,跳过 0 个 ==========
*/
直接编译不过…
看官方说明 file:///D:/3rd_prj/crypt/openssl-3.2.0/doc/html/man3/OPENSSL_malloc.html
The following functions have been deprecated since OpenSSL 3.0, and can be hidden entirely by defining OPENSSL_API_COMPAT with a suitable version value, see openssl_user_macros(7):
int CRYPTO_mem_leaks(BIO *b);
int CRYPTO_mem_leaks_fp(FILE *fp);
int CRYPTO_mem_leaks_cb(int (*cb)(const char *str, size_t len, void *u),
void *u);
int CRYPTO_set_mem_debug(int onoff);
int CRYPTO_mem_ctrl(int mode);
int OPENSSL_mem_debug_push(const char *info);
int OPENSSL_mem_debug_pop(void);
int CRYPTO_mem_debug_push(const char *info, const char *file, int line);
int CRYPTO_mem_debug_pop(void);
DESCRIPTION
看到官方说, 这些内存诊断函数已经弃用了, 用clang的检查代替(忘了是哪个文档了, 反正是官方文档中说的).
去看内存诊断函数的实现, 都是空的, 官方确实已经弃用了.
尝试将vs2019的工具链改为clang, 看不到效果, 且不能单步进入库函数内部.
用clang工具链编译, 可以编译过, 也可以运行, 不过无法进入调试版的pdb实现中.
已启动重新生成…
1>------ 已启动全部重新生成: 项目: prj_template, 配置: Debug x64 ------
1>main.cpp(12,2): warning : 'CRYPTO_mem_leaks' is deprecated: Since OpenSSL 3.0 [-Wdeprecated-declarations]
1>D:\my_dev\lib\openssl_3d2\include\openssl/crypto.h(411,1): message : 'CRYPTO_mem_leaks' has been explicitly marked deprecated here
1>D:\my_dev\lib\openssl_3d2\include\openssl/macros.h(194,49): message : expanded from macro 'OSSL_DEPRECATEDIN_3_0'
1>D:\my_dev\lib\openssl_3d2\include\openssl/macros.h(44,22): message : expanded from macro 'OSSL_DEPRECATED'
1>prj_template.vcxproj -> D:\my_dev\my_local_git_prj\study\openSSL\exp\call_mem_leak_API\x64\Debug\prj_template.exe
1>'pwsh.exe' 不是内部或外部命令,也不是可运行的程序
1>或批处理文件。
1>已完成生成项目“prj_template.vcxproj”的操作。
========== 全部重新生成: 成功 1 个,失败 0 个,跳过 0 个 ==========
那就不用clang来编译.
看看有没有替代内存诊断的方法?
找到一个opensslAPI CRYPTO_get_alloc_counts(), 可以取当前内存分配次数.
将这个API封装一下, 卡在openssl应用函数外边, 就可以间接的知道是否有内存泄漏, 如果有opensslAPI调用引起的内存泄漏, 可以迅速的缩小排查范围.
main.cpp
/*!
* \file main.cpp
*/
#include "my_openSSL_lib.h"
#include <openssl/crypto.h>
bool is_OSSL_mem_leak();
void test_mem_leak(bool b_have_mem_leak);
int main(int argc, char** argv)
{
openssl_mdebug_begin();
test_mem_leak(true);
openssl_mdebug_end(true, false); // 如果需要断言, 参数2为true
openssl_mdebug_begin();
test_mem_leak(false);
openssl_mdebug_end(true, true);
/*
run result
test_mem_leak(test have mem leak)
>> malloc_count = 0, realloc_count = 0, free_count = 0
<< malloc_count = 1, realloc_count = 0, free_count = 0
err : !!! mem leak happen
test_mem_leak(test no mem leak)
*/
return 0;
}
void test_mem_leak(bool b_have_mem_leak)
{
void* pBuf = NULL;
printf("test_mem_leak(%s)\n", (b_have_mem_leak ? "test have mem leak" : "test no mem leak"));
pBuf = OPENSSL_malloc(2);
// do some task ...
if (!b_have_mem_leak)
{
OPENSSL_free(pBuf);
pBuf = NULL;
}
}
my_openSSL_lib.h
/*!
\file my_openSSL_lib.h
*/
#ifndef __MY_OPENSSL_LIB_H__
#define __MY_OPENSSL_LIB_H__
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib") // for select()
#include <windows.h>
#include <stdbool.h>
#pragma comment(lib, "libcrypto.lib")
#pragma comment(lib, "libssl.lib")
#endif /* #ifdef _WIN32 */
// --------------------------------------------------------------------------------
// 开关宏 - begin
// --------------------------------------------------------------------------------
#define MY_USE_APPLINK
// --------------------------------------------------------------------------------
// 开关宏 - END
// --------------------------------------------------------------------------------
typedef struct _tag_openssl_mem_counter{
int malloc_count_begin;
int realloc_count_begin;
int free_count_begin;
int malloc_count_end;
int realloc_count_end;
int free_count_end;
} TAG_OPENSSL_MEM_COUNTER;
void openssl_mdebug_begin();
bool openssl_mdebug_end(bool show_tip, bool b_assert);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef __MY_OPENSSL_LIB_H__ */
my_openSSL_lib.c
/*!
* \file D:\my_dev\my_local_git_prj\study\openSSL\nmake_test\test_c\prj_005_afalgtest.c\my_openSSL_lib.c
*/
#include "my_openSSL_lib.h"
#include "openssl/crypto.h" // for CRYPTO_get_alloc_counts
#include <assert.h>
#ifdef MY_USE_APPLINK
#include <openssl/applink.c> /*! for OPENSSL_Uplink(00007FF8B7EF0FE8,08): no OPENSSL_Applink */
#endif // #ifdef MY_USE_APPLINK
static TAG_OPENSSL_MEM_COUNTER gs_openssl_mdebug;
void openssl_mdebug_begin()
{
CRYPTO_get_alloc_counts(&gs_openssl_mdebug.malloc_count_begin, &gs_openssl_mdebug.realloc_count_begin, &gs_openssl_mdebug.free_count_begin);
}
bool openssl_mdebug_end(bool show_tip, bool b_assert)
{
bool b_rc = false;
long lCntBegin = 0;
long lCntEnd = 0;
CRYPTO_get_alloc_counts(&gs_openssl_mdebug.malloc_count_end, &gs_openssl_mdebug.realloc_count_end, &gs_openssl_mdebug.free_count_end);
lCntBegin = gs_openssl_mdebug.malloc_count_begin + gs_openssl_mdebug.realloc_count_begin - gs_openssl_mdebug.free_count_begin;
lCntEnd = gs_openssl_mdebug.malloc_count_end + gs_openssl_mdebug.realloc_count_end - gs_openssl_mdebug.free_count_end;
b_rc = (lCntBegin == lCntEnd);
if (!b_rc && show_tip)
{
printf(">> malloc_count = %d, realloc_count = %d, free_count = %d\n", gs_openssl_mdebug.malloc_count_begin, gs_openssl_mdebug.realloc_count_begin, gs_openssl_mdebug.free_count_begin);
printf("<< malloc_count = %d, realloc_count = %d, free_count = %d\n", gs_openssl_mdebug.malloc_count_end, gs_openssl_mdebug.realloc_count_end, gs_openssl_mdebug.free_count_end);
printf("err : !!! mem leak happen\n");
}
if (b_assert)
{
assert(true == b_rc);
}
return b_rc;
}
备注
以后有机缘再查查怎么用clang来查openssl应用是否有内存泄漏.
查资料时, 很多情况下都不是想查就能查到的.
很多时候, 是心里带着问题, 查其他资料时, 突然给了启发, 才将以前的问题搞掉.
这种调用CRYPTO_get_alloc_counts()来间接的排查是否调用opensslAPI时, 是否没有成对的分配,释放内存.
没有那么直接和方便, 不过也算是一种方法了. 有总比没有强.
希望以后能找到其他更好的方法来定位opensslAPI调用时的内存泄漏点.
备注
openssl的编译检查, 测试用例还是很严格的.
对外提供的API, 都有测试程序.
CRYPTO_get_alloc_counts()这个API的调用, 也能找到至少一处.
用SI将openssl源码编译的目录中的能识别的东东都包进来搜索, 必然能看到测试用例或者API调用的痕迹.
如果某个API虽然定义, 但是官方源码编译目录的实现中都没有用到, 那么咱么就不能用这个API.
这招不行啊
今天正好写个测试程序, 用到了这种内存泄漏检测方法. 有断言, 不好使.
int main(int argc, char** argv)
{
BIO* bio = NULL;
openssl_mdebug_begin();
test_bio_mem_leak();
// test_bio_new_mem_buf();
openssl_mdebug_end(false, true);
return 0;
}
void test_bio_mem_leak(void)
{
BIO* bio = BIO_new_mem_buf("Hello World\n", 12);
BIO_free(bio);
}
只能先关注这事, 以后再想办法了.
跟了一下openssl代码, 是产生默认库上下文中有很多openssl_malloc()引起的内存分配.
后续再看看, 自己显势调用产生销毁默认上下文的API, 是否可以继续用这种方法.
显势调用默认上下文也不行
int main(int argc, char** argv)
{
OSSL_LIB_CTX* _ossl_lib_ctx = NULL;
BIO* bio = NULL;
do {
openssl_mdebug_begin();
_ossl_lib_ctx = OSSL_LIB_CTX_get0_global_default();
if (NULL == _ossl_lib_ctx)
{
assert(false);
break;
}
test_bio_mem_leak();
// test_bio_new_mem_buf();
OSSL_LIB_CTX_free(_ossl_lib_ctx);
openssl_mdebug_end(true, false); // 到这里, 还是报错
} while (false);
return 0;
}
void test_bio_mem_leak(void)
{
BIO* bio = BIO_new_mem_buf("Hello World\n", 12);
BIO_free(bio);
}
报错原因, openssl函数调用中, 会有其他默认的上下文建立会调用内存分配.
具体是啥函数, 要去单步.
这种用内存分配计数的方法, 不能真实的间接观察到openssl内部的内存泄漏, 做了一个没用的实验…
还是要老老实实的看官方例子, 手工调用对应API的释放函数.
找到一种还可以的解决方法, 现在看来可以准确观测到openssl内存泄漏点
openssl设计的可以, 预留了很多有用的API.
翻翻openssl提供的API, 找到了以下有用的API.
CRYPTO_get_mem_functions()
CRYPTO_set_mem_functions()
OPENSSL_init_crypto()
OPENSSL_cleanup()
这些可以用于辅助观测openssl内存泄漏点, 不止是openssl API, openssl内部发生的内存泄漏也能观测到(如果有的话)
内存泄漏观测的程序实现
main.cpp
/*!
* \file main.cpp
*/
#include "my_openSSL_lib.h"
#include <openssl/crypto.h>
#include <openssl/bio.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "CMemHookRec.h"
void test_bio_mem_leak(bool b_have_mem_leak);
int main(int argc, char** argv)
{
setvbuf(stdout, NULL, _IONBF, 0); // 清掉stdout缓存, 防止调用printf时阻塞
// mem IF hook, 必须在执行任何openssl API之前替换
mem_hook();
// 自己的openssl接口应用
test_bio_mem_leak(true);
test_bio_mem_leak(false);
// mem IF un hook, 必须在openssl结束后, 再恢复原始函数
mem_unhook();
/* run result, 如果有openssl应用接口没释放引起的内存泄漏, 有断言, stdout有输出
一个openssl API引起的内存泄漏可能对应这多条内存分配记录, 不过排查范围缩小多了, 线索也清晰多了
结合对自己的openssl调用代码块的注释排除法, 很容易找到自己哪里没调用正确的openssl释放API.
free map, g_mem_hook_map.size() = 4
2AAA2F36560 128 crypto\bio\bio_lib.c:83
2AAA2F4EC40 16 crypto\bio\bss_mem.c:111
2AAA2FEA470 32 crypto\bio\bss_mem.c:119
2AAA2FEAA10 32 crypto\buffer\buffer.c:35
error : !!! find openssl call memory leak
Assertion failed: false, file D:\my_dev\my_local_git_prj\soft\xx\src\case\exp002_mem_hook\main.cpp, line 57
*/
return 0;
}
void test_bio_mem_leak(bool b_have_mem_leak)
{
BIO* bio = BIO_new_mem_buf("Hello World\n", 12);
if (false == b_have_mem_leak)
{
BIO_free(bio);
}
}
找内存泄漏时很方便, 只要在程序入口处调用mem_hook(), 然后自己正常调用openssl API, 程序结束前调用mem_unhook()
如果有openssl 释放API没调用引起的内存泄漏, 就会有断言.
如果是控制台程序, 就可以直接看到内存泄漏点.
如果不是控制台程序, 将mem_unhook()中的内存泄漏改写到其他输出(e.g. 文件).
这排查起来就容易多了.
CMemHookRec.h
/*!
\file CMemHookRec.h
\note openssl 分配API hook 之后, 记录的内存分配记录
*/
#ifndef __CMEMHOOKREC_H__
#define __CMEMHOOKREC_H__
void mem_hook();
void mem_unhook();
#endif // #ifndef __CMEMHOOKREC_H__
CMemHookRec.cpp
/// \file CMemHookRec.cpp
#include "pch.h"
#include <cstdint>
#include <stdio.h>
#include <map>
#include <openssl/crypto.h>
#include "CMemHookRec.h"
#include <assert.h>
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) \
do { \
if (NULL != (p)) { \
delete (p);\
} \
(p)=NULL; \
} while (0);
#endif // #ifndef SAFE_DELETE
class CMemHookRec
{
public:
void show_info();
public:
uint64_t u64_addr;
size_t num;
const char* file;
int line;
uint64_t rec_sn;
};
static std::map<uint64_t, CMemHookRec*> g_mem_hook_map;
typedef std::pair<uint64_t, CMemHookRec*> Map_Pair_mem_hook;
typedef std::map<uint64_t, CMemHookRec*>::iterator It_mem_hook;
// malloc_fn_org 0x00007ffb0796614f {libcrypto-3-x64.dll!CRYPTO_malloc} void *(*)(unsigned __int64, const char *, int)
static CRYPTO_malloc_fn malloc_fn_org = NULL;
// realloc_fn_org 0x00007ffb07967a1d {libcrypto-3-x64.dll!CRYPTO_realloc} void *(*)(void *, unsigned __int64, const char *, int)
static CRYPTO_realloc_fn realloc_fn_org = NULL;
// free_fn_org 0x00007ffb079631b1 {libcrypto-3-x64.dll!CRYPTO_free} void(*)(void *, const char *, int)
static CRYPTO_free_fn free_fn_org = NULL;
static OPENSSL_INIT_SETTINGS* gp_ossl_init_setting = NULL;
static uint64_t g_u64_malloc_cnt_all = 0;
static void* my_CRYPTO_malloc(size_t num, const char* file, int line);
static void* my_CRYPTO_realloc(void* addr, size_t num, const char* file, int line);
static void my_CRYPTO_free(void* ptr, const char* file, int line);
static bool free_map();
static std::wstring my_A2W(std::string str);
void CMemHookRec::show_info()
{
#ifdef _MFC_VER
TRACE(TEXT("entry sn = [%I64d], %I64X %zu %s:%d\n"), this->rec_sn, u64_addr, num, ((NULL != file) ? my_A2W(file).data() : TEXT("NULL")), line);
#else
printf("entry sn = [%I64d], %I64X %zu %s:%d\n", this->rec_sn, u64_addr, num, ((NULL != file) ? file : "NULL"), line);
#endif // #ifdef _MFC_VER
}
void mem_hook()
{
int i_rc = 0;
uint64_t u64_init_opt = 0;
CRYPTO_get_mem_functions(&malloc_fn_org, &realloc_fn_org, &free_fn_org);
CRYPTO_set_mem_functions(my_CRYPTO_malloc, my_CRYPTO_realloc, my_CRYPTO_free);
// openssl init all
gp_ossl_init_setting = OPENSSL_INIT_new(); // 必须用OPENSSL_INIT_free()释放, 否则有24个字节的泄漏
u64_init_opt = OPENSSL_INIT_LOAD_CRYPTO_STRINGS |
OPENSSL_INIT_ADD_ALL_CIPHERS |
OPENSSL_INIT_ADD_ALL_DIGESTS |
OPENSSL_INIT_LOAD_CONFIG |
OPENSSL_INIT_ASYNC |
OPENSSL_INIT_NO_ATEXIT;
// 将openssl库中的静态初始化函数显势调用一下, 免得在我们手工调用API时(因为有些openssl对象或变量没初始化)自动调用静态初始化函数引起多余的非我们应用产生的内存分配
// 初始化函数在应用中只能调用一次.
i_rc = OPENSSL_init_crypto(u64_init_opt, gp_ossl_init_setting);
assert(1 == i_rc);
}
void mem_unhook()
{
// openssl uninit all
// 只能调用一次
OPENSSL_cleanup();
// 必须在openssl cleanup之后调用map显示, 这样才能过滤掉系统自动分配的内存.
// 如果map不为空, 这些记录才是我们自己应用没释放的内存
// 在free_map()时, 如果看到多条未被释放的内存, 也一定是那么多个API调用没释放, 因为一条openssl API会对应者多个openssl_mallc(), e.g. BIO_new_mem_buf() 就有4个内存分配动作.
if (!free_map())
{
printf("error : !!! find openssl call memory leak\r\n");
assert(false);
/* run result
free map, g_mem_hook_map.size() = 4
2AAA2F36560 128 crypto\bio\bio_lib.c:83
2AAA2F4EC40 16 crypto\bio\bss_mem.c:111
2AAA2FEA470 32 crypto\bio\bss_mem.c:119
2AAA2FEAA10 32 crypto\buffer\buffer.c:35
error : !!! find openssl call memory leak
Assertion failed: false, file D:\my_dev\my_local_git_prj\soft\krgy_software_protect\src\case\exp002_mem_hook\main.cpp, line 57
*/
}
if (NULL != gp_ossl_init_setting)
{
OPENSSL_INIT_free(gp_ossl_init_setting);
gp_ossl_init_setting = NULL;
}
CRYPTO_set_mem_functions(malloc_fn_org, realloc_fn_org, free_fn_org);
}
static std::wstring my_A2W(std::string str)
{
USES_CONVERSION;
std::wstring str_rc = A2W(str.c_str());
return str_rc;
}
static bool free_map()
{
It_mem_hook it = g_mem_hook_map.end();
size_t size = g_mem_hook_map.size();
#ifdef _MFC_VER
TRACE(TEXT("free mem_hook map, g_mem_hook_map.size() = %zd, %s openssl API call memory leak\n"), size, ((size > 0) ? TEXT("have") : TEXT("no")));
#else
printf("free mem_hook map, g_mem_hook_map.size() = %zd, %s openssl API call memory leak\n", size, ((size > 0) ? "have" : "no"));
#endif // #ifdef _AFXDLL
for (it = g_mem_hook_map.begin(); it != g_mem_hook_map.end(); it++) {
if (NULL != it->second) {
it->second->show_info();
}
SAFE_DELETE(it->second);
}
g_mem_hook_map.clear();
return (0 == size);
}
static void* my_CRYPTO_malloc(size_t num, const char* file, int line)
{
void* p = NULL;
It_mem_hook it;
CMemHookRec* rec = NULL;
p = malloc(num);
if (NULL != p)
{
it = g_mem_hook_map.find((uint64_t)p);
if (it != g_mem_hook_map.end()) {
// printf("find key\n");
assert(false);
}
else {
// printf("not find key\n");
rec = new CMemHookRec();
if (NULL != rec)
{
rec->rec_sn = ++g_u64_malloc_cnt_all;
if (2225 == rec->rec_sn)
{
rec->rec_sn = rec->rec_sn; // for debug mem leak
}
rec->u64_addr = (uint64_t)p;
rec->num = num;
rec->file = file;
rec->line = line;
g_mem_hook_map.insert(Map_Pair_mem_hook(rec->u64_addr, rec));
}
}
}
return p;
}
static void* my_CRYPTO_realloc(void* addr, size_t num, const char* file, int line)
{
void* p = NULL;
It_mem_hook it;
CMemHookRec* rec = NULL;
p = realloc(addr, num);
if (NULL != p)
{
it = g_mem_hook_map.find((uint64_t)addr);
if (it != g_mem_hook_map.end()) {
// printf("find key\n");
SAFE_DELETE(it->second);
g_mem_hook_map.erase(it);
}
rec = new CMemHookRec();
if (NULL != rec)
{
rec->rec_sn = ++g_u64_malloc_cnt_all;
rec->u64_addr = (uint64_t)p;
rec->num = num;
rec->file = file;
rec->line = line;
g_mem_hook_map.insert(Map_Pair_mem_hook(rec->u64_addr, rec));
}
}
return p;
}
static void my_CRYPTO_free(void* ptr, const char* file, int line)
{
It_mem_hook it;
CMemHookRec* rec = NULL;
if (NULL != ptr)
{
free(ptr);
it = g_mem_hook_map.find((uint64_t)ptr);
if (it != g_mem_hook_map.end()) {
// printf("find key\n");
SAFE_DELETE(it->second);
g_mem_hook_map.erase(it);
}
else {
// printf("not find key\n");
assert(false);
}
}
}
备注
此笔记前面实验的CRYPTO_get_alloc_counts()方法, 在mem_hook中用不了了, 因为将内存分配函数换掉了.
不过, 可以在上面这个实验上改改, 不hook内存分配函数, 只用 OPENSSL_init_crypto() + OPENSSL_cleanup() + CRYPTO_get_alloc_counts(), 应该也能看到内存泄漏的计数, 但是看不到哪个文件哪行发生的泄漏.
因为这个想法不好, 我就没去再实验.
毕竟有多个解决方法, 只取最优的那个.
mem_hook()这个方法好, 能看到发生泄漏的具体库文件和行数, 排查起来可操作性强.
备注
将 void CMemHookRec::show_info()的输出改了一下, 上面的实验代码已经更新.
void CMemHookRec::show_info()
{
printf("entry sn = [%I64d], %I64X %zu %s:%d\n", this->rec_sn, u64_addr, num, ((NULL != file) ? file : "NULL"), line);
}
这样的话, 等观测到内存泄漏时, 号码连续的就是一个openssl API的调用引起的内存泄漏, 更方便调试排查.
备注
- 修正了内存泄漏 add OPENSSL_INIT_free(gp_ossl_init_setting);
- 更新了输出格式,适应控制台和MFC程序
END
更多推荐
所有评论(0)