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

news2025/1/16 4:45:50

文章目录

    • 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.
在这里插入图片描述

END

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

sonar-java 手写一个规则-单元测试分析

前言 最近做项目&#xff0c;定制sonar规则&#xff0c;提高Java代码质量&#xff0c;在编写的sonar规则&#xff0c;做验证时&#xff0c;使用单元测试有一些简单的心得感悟&#xff0c;分享出来。 自定义规则模式 sonar的自定义规则很简单&#xff0c;一般而言有2种模式可…

解决vulhub漏洞环境下载慢卡死问题即解决docker-valhub漏洞环境下载慢的问题

解决vulhub环境下载慢/卡 当前环境为&#xff1a;ubuntu20 1.在 cd /etc/docker/目录下创建或修改daemon.json文件 sudo touch daemon.json编辑daemon.json文件 sudo vim daemon.json2.填写阿里云镜像地址&#xff1a; { "registry-mirrors":["https://6kx…

UE5 C++ Gas开发 学习记录(三)

添加AuraPlayerState,AuraAbilitySystemComponentBase和AuraAttributeSet 在Build.cs里添加 // Copyright Epic Games, Inc. All Rights Reserved. using UnrealBuildTool; public class MyGas : ModuleRules { public MyGas(ReadOnlyTargetRules Target) : base(Target) { P…

Android pixel6网页线刷官方镜像

背景 p6-7系pixel更新Android 13,首次引入了防回滚机制,Android13系统检测到属于Android12版本的旧bootloader就会直接红字警告拒绝引导,多次引导就会成为收藏品!(除非充钱) 今天收到了新的pixel6,想着以后刷机刷内核肯定频繁,就先打个预防针。 网页线刷官方镜像 查…

RabbitMQ-消息队列:优先级队列、惰性队列

20、优先级队列 在我们系统中有一个订单催付的场景&#xff0c;我们的客户在天猫下的订单&#xff0c;淘宝会及时将订单推送给我们&#xff0c;如果在用户设定的时间内未付款那么就会给用户推送一条短信提醒&#xff0c;很简单的一个功能对吧。 但是&#xff0c;天猫商家对我…

如何增加层次厚度?

Q 老师&#xff0c;我在做一个斧头武器&#xff0c;如何在平面上增加厚度和层次呢&#xff1f; A 选中这几个线&#xff0c;点连接就会出现中线&#xff0c;把中线稍作调整即可~

[嵌入式系统-35]:RT-Thread -20- 新手指南:在Keil MDK-ARM 模拟器上运行RT-Thread

目录 前言&#xff1a; 一、Keil MDK-ARM 模拟器概述 1.1 Keil概述 1.2 Keil MDK-ARM 1.3 Keil MDK-ARM软件仿真模拟器 1.4 Keil模拟器支持的CPU类型 二、Keil MDK ARM安装 前言&#xff1a; 一般嵌入式操作系统因为它的特殊性&#xff0c;往往和硬件平台密切相关连&am…

【C++精简版回顾】12.友元函数

1.友元函数 1.class class MM { public:MM(int age,string name):age(age),name(name){}friend void print(MM mm); private:int age;string name;void print() {cout << age << "岁的" << name << "喜欢你" << endl;} }; f…

DAY31--learning English

一、积累 1.stiff 2.curve 3.pungent 4.mellow 5.marinate 6.drain 7.corrupt 8.magnet 9.liver 10.stew 11.maid 12.sonogram 13.folk 14.anecdote 15.altar 16.spaghetti 17.ammunition 18.shield 19.beacon 20.hanger 二、练习 1.牛津原译 stiff /stɪf/ ( stiffer stiff…

编程的基础:理解时间和空间复杂度

编程的基础&#xff1a;理解时间和空间复杂度 时间复杂度空间复杂度示例常数时间复杂度 O(1)线性时间复杂度 O(n)线性对数时间复杂度 O(n log n)二次时间复杂度 O(n^2)指数时间复杂度 O(2^n) 空间复杂度示例常数空间复杂度 O(1)线性空间复杂度 O(n)线性对数空间复杂度 O(log n)…

流浪动物救助平台:Java开发的实践与思考

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

获取tensorflow lite模型指定中间层的输出

以mobilenet v2为例子&#xff0c;我已经训练好了模型&#xff0c;有tflite格式和onnx格式两种模型的权重文件&#xff0c;我想获取tflite模型在推理阶段neck部分的输出。 查看onnx模型得到neck最后一层位置 使用netron查看onnx模型结构 从name中能知道Reshape是neck的最后一…

【蓝桥杯】拓扑排序

一.拓扑排序 1.定义&#xff1a; 设G&#xff08;V&#xff0c;E&#xff09;是一个具有n个顶点的有向图&#xff0c;V中的顶点序列称为一个拓扑序列&#xff0c;当且仅当满足下列条件&#xff1a;若从顶点到有一条路径&#xff0c;则在顶点序列中顶点必在之前。 2.基本思想…

前端学习---- 前端HTML基本元素的介绍

一&#xff1a;显示相关的HTML基础知识 1. 推荐的前端编写工具 2. VScode的html速写规则&#xff08;从a标签开始再用&#xff09; ①、&#xff01;&#xff1a;代表生成html的基本框架元素 ②、html元素&#xff1a;直接书写html,不需要加<>,按回车会自动生成 ③、{}…

社交媒体变革者:剖析Facebook对在线互动的贡献

随着数字化时代的蓬勃发展&#xff0c;社交媒体已经成为人们日常生活中不可或缺的一部分。在这个领域的发展中&#xff0c;Facebook作为先行者和领导者&#xff0c;对在线互动的演变和发展产生了深远的影响。本文将深入剖析Facebook在社交媒体领域的贡献&#xff0c;以及它对在…

✅鉴权—cookie、session、token、jwt、单点登录

基于 HTTP 的前端鉴权背景cookie 为什么是最方便的存储方案&#xff0c;有哪些操作 cookie 的方式session 方案是如何实现的&#xff0c;存在哪些问题token 是如何实现的&#xff0c;如何进行编码和防篡改&#xff1f;jwt 是做什么的&#xff1f;refresh token 的实现和意义ses…

探索水下低光照图像检测性能,基于YOLOv6全系列【n/s/m/l】参数模型开发构建海底生物检测识别分析系统

底这类特殊数据场景下的检测模型开发相对来说比较少&#xff0c;在前面的博文中也有一些涉及&#xff0c;感兴趣的话可以自行移步阅读即可&#xff1a; 试探索水下目标检测&#xff0c;基于yolov5轻量级系列模型n/s/m开发构建海底生物检测系统》 《基于YOLOv5C3CBAMCBAM注意力…

查看笔记本电池健康状态-windows11

在 Windows 11 中获取详细的电池报告 Windows 11 中内置的 Powerfg 命令行选项来生成电池报告。 在任务栏上选择“搜索”&#xff0c;键入“cmd”&#xff0c;长按&#xff08;或右键单击&#xff09;“命令提示符”&#xff0c;然后选择“以管理员身份运行” ->“是”。 …

springboot215基于springboot技术的美食烹饪互动平台的设计与实现

美食烹饪互动平台的设计与实现 摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统美食信息管理难度大&…

【电子书】数据库

资料 wx&#xff1a;1945423050 整理了一些互联网电子书&#xff0c;推荐给大家 数据库 ClickHouse原理解析与应用实践.epubECharts数据可视化&#xff1a;入门、实战与进阶.epubHAWQ数据仓库与数据挖掘实战.epubHBase不睡觉书.epubHBase原理与实践.epubMySQL 5.7从零开始学&…