openssl3.2 - crypto-mdebug被弃用后, 内存泄漏检查的替代方法

文章目录

    • openssl3.2 - crypto-mdebug被弃用后, 内存泄漏检查的替代方法
    • 概述
    • 笔记
    • 查看特性列表
    • openssl3.2编译脚本 - 加入enable-crypto-mdebug
    • 看看有没有替代内存诊断的方法?
    • main.cpp
    • my_openSSL_lib.h
    • my_openSSL_lib.c
    • 备注
    • 备注
    • 这招不行啊
    • 显势调用默认上下文也不行
    • END

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的释放函数.

END

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/410879.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【设计模式】工厂模式、建造者模式、原型设计模式

文章目录 1、简单工厂模式2、工厂方法模式3、抽象工厂模式4、建造者模式5、原型设计模式 设计模式即总结出来的一些最佳实现。23种设计模式可分为三大类&#xff1a; 创建型模式&#xff1a;隐藏了创建对象的过程&#xff0c;通过逻辑方法进行创建对象&#xff0c;而不是直接n…

【python开发】面向对象高级和应用

这里写目录标题 一、继承&#xff08;一&#xff09;mro和c3算法&#xff08;二&#xff09;py2和py3区别&#xff08;了解即可&#xff09; 二、内置函数补充&#xff08;一&#xff09;callable&#xff1a;是否可以在后面加括号执行&#xff08;二&#xff09;super()&#…

雷达一维成像:基于数据集的实践

雷达一维成像&#xff1a;基于数据集的实践 (距离压缩\距离-时间图\距离-多普勒图\微多普勒图) 说明 雷达成像技术是雷达发展的一个重要里程碑&#xff1a;从此雷达的功能不仅仅是将所观测的对象视为点目标&#xff0c;并只测量它的位置与运动参数。雷达成像技术使得我们可以获…

EMQX Enterprise 5.5 发布:新增 Elasticsearch 数据集成

EMQX Enterprise 5.5.0 版本已正式发布&#xff01; 在这个版本中&#xff0c;我们引入了一系列新的功能和改进&#xff0c;包括对 Elasticsearch 的集成、Apache IoTDB 和 OpenTSDB 数据集成优化、授权缓存支持排除主题等功能。此外&#xff0c;新版本还进行了多项改进以及 B…

Linux第63步_为新创建的虚拟机添加必要的目录和安装支持linux系统移植的软件

1、创建必要的目录 输入密码“123456”&#xff0c;登录虚拟机 这个“zgq”&#xff0c;是用户名&#xff0c;也是下面用到的的“zgq”目录。 1)、创建“/home/zgq/linux/”目录 打开终端&#xff0c;进入“/home/zgq/”目录 输入“mkdir linux回车”&#xff0c;创建“/ho…

电子版证件照怎么弄?分享完整制作方法!

在数字化时代&#xff0c;电子版证件照已成为我们生活中不可或缺的一部分。无论是求职、办理证件还是网络注册&#xff0c;都需要用到电子版证件照。那么&#xff0c;如何制作一份合格的电子版证件照呢&#xff1f;本文将为您详细介绍电子版证件照的制作方法&#xff0c;并推荐…

开年大吉!安全狗入选工信部工业互联网试点示范名单

近日&#xff0c;工业和信息化部信息通信管理局公布了2023年工业互联网试点示范名单。此次名单根据《工业和信息化部办公厅关于组织开展2023年工业互联网试点示范项目申报工作的通知》&#xff08;工信厅信管函﹝2023﹞319号&#xff09;&#xff0c;经企业申报、地方推荐、专家…

通过OCR实现纯数字识别

基于飞浆paddle训练框架 照这个改的 https://www.paddlepaddle.org.cn/documentation/docs/zh/practices/cv/image_ocr.html 训练不到10分钟 10epoch cpu&#xff1a;inter i5 8250 U 脚本生成的图10000 验证训练&#xff1a;3:7 预测结果 chatgpt写的代码&#xff0c;生成数…

从ChatGPT到Sora,来了解大模型训练中的存储

1 从chatGPT到Sora 2022年底&#xff0c;OpenAI推出人工智能聊天机器人ChatGPT&#xff0c;开启了大模型领域的“竞速跑”模式。2024年2月15日&#xff0c;随着视频生成模型Sora的横空出世&#xff0c;OpenAI再度掀起热潮。 Sora将视频生成内容拉到了一个全新的高度&#xff0c…

Pybind11 在C++中运行python脚本操作内存数据

pybind11资料 官方Github:Pybind11 Github Pybind11文档&#xff1a;Pybind11 文档 文档在深入使用后需要细细读懂&#xff0c;包括全局只能有一个解释器&#xff0c;如何从C中返回指针/引用等。基本文档中需要注意的点都会遇到 Python环境安装及维护 对于正常使用人员&…

python自动化测试三部曲之request+django实现接口测试

这里废话少说&#xff0c;进入正题 我的思路是这样的 1、先用django实现登陆、增加、删除、查看4个接口 2、在excel定义好测试案例、然后读取excel中的案例&#xff0c;然后把案例用unittest框架组装和封装 3、启动django&#xff0c;执行测试案例 一、先跑通unittest到dj…

Scikit-Learn逻辑回归

Scikit-Learn逻辑回归 1、逻辑回归概述1.1、逻辑回归1.2、逻辑回归的优缺点1.3、逻辑回归与线性回归 2、逻辑回归的原理2.1、逻辑回归的概念与原理2.2、逻辑回归的损失函数 3、 1、逻辑回归概述 1.1、逻辑回归 逻辑回归&#xff08;Logistic Regression&#xff09;主要解决二…

【IDEA】java 项目启动偶现Kotlin 版本问题 error:Kotlin:module was

一、问题描述&#xff1a; error:Kotlin:module was compiled with an incompatible version of kotlin the binary version of its metadata is二、问题原因&#xff1a; jar包版本冲突 三、解决方式&#xff1a; 1、Rebuild Project&#xff08;推荐☆&#xff09; 重新构…

【web】云导航项目部署及环境搭建(复杂)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、项目介绍1.1项目环境架构LNMP1.2项目代码说明 二、项目环境搭建2.1 Nginx安装2.2 php安装2.3 nginx配置和php配置2.3.1 修改nginx文件2.3.2 修改vim /etc/p…

内存溢出排查

1、进入k8s容器对应服务节点查看进程号 ps aux|grep javaps aux 是用BSD的格式来显示 java这个进程 显示的项目有&#xff1a;USER , PID , %CPU , %MEM , VSZ , RSS , TTY , STAT , START , TIME , COMMAND USER: 行程拥有者 PID: pid %CPU: 占用的 CPU 使用率 %MEM: 占用的记…

python Airtest自动化测试工具的的使用

Airtest全称AirtestProject&#xff0c;是由网易游戏推出的一款自动化测试框架&#xff0c;在软件测试的时候使用到了该框架。这里记录一下安装、使用和遇到的坑的问题… Airtest的官网介绍项目构成 Airtest&#xff1a;是一个跨平台的、基于图像识别的UI自动化测试框架&#x…

YOLOv9尝鲜测试五分钟极简配置

pip安装python包&#xff1a; pip install yolov9pip在https://github.com/WongKinYiu/yolov9/tree/main中下载好权重文件yolov9-c.pt。 运行下面代码&#xff1a; import yolov9model yolov9.load("yolov9-c.pt", device"cpu") # load pretrained or c…

观察者模式与发布订阅模式

观察者模式 定义&#xff1a; 观察者模式是一种行为型设计模式&#xff0c;定义对象间的一种一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知并被自动更新。 结构图&#xff1a; ES6简易代码实现&#xff1a; //ts环境下…

Uncertainty-Aware Mean Teacher(UA-MT)

Uncertainty-Aware Mean Teacher 0 FQA:1 UA-MT1.1 Introduction:1.2 semi-supervised segmentation1.3 Uncertainty-Aware Mean Teacher Framework 参考&#xff1a; 0 FQA: Q1: 不确定感知是什么意思&#xff1f;不确定信息是啥&#xff1f;Q2&#xff1a;这篇文章的精妙的点…

300分钟吃透分布式缓存-14讲:大数据时代,MC如何应对新的常见问题?

大数据时代 Memcached 经典问题 随着互联网的快速发展和普及&#xff0c;人类进入了大数据时代。在大数据时代&#xff0c;移动设备全面融入了人们的工作和生活&#xff0c;各种数据以前所未有的 速度被生产、挖掘和消费。移动互联网系统也不断演进和发展&#xff0c;存储、计…