内存泄漏检测组件的实现

news2024/10/6 22:20:47
  1. 通过宏定义来包装 mallocfree 函数,以便在每次内存分配和释放时记录相关信息,如文件名和行号。这使得你能够跟踪哪个函数在哪里分配和释放内存。

#define _GNU_SOURCE
#include <dlfcn.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <link.h>


// 方式一:宏定义

void *_malloc(size_t size, char *filename,int line) {

    void *ptr = malloc(size);
    
    char file[128] = {0};
    sprintf(file ,"./mem/%p.mem" ,ptr);
    FILE *fp = fopen(file ,"w");//w小写

    fprintf(fp, "[+]addr: %p filename: %s line: %d\n",ptr,filename,line);

    fflush(fp);
    fclose(fp);

    return ptr;
}

void _free(void *ptr, char *filename,int line) {

    char file[128] = {0};
    sprintf(file,"./mem/%p.mem",ptr);

    if(unlink(file) < 0){//unlink用于在文件系统中删除指定的文件
        printf("double free %p\n",ptr);
        return;
    }

    return free(ptr);

}

// __FILE__ 获取文件名
// __LINE__ 获取函数执行的行号

#define malloc(size)   _malloc(size, __FILE__,__LINE__)
#define free(ptr)      _free(ptr, __FILE__,__LINE__)

int main(void) {

    init_hook();

    void *p1 = malloc(8);
    void *p2 = malloc(16);
    void *p3 = malloc(32);

    free(p1);
    free(p2);

    return 0;
}

编译执行: 

 表示在memleak.c 文件中, 第149行出现内存泄漏问题。

2.通过使用hook方法来重定向 mallocfree 函数, 与此同时通过__builtin_return_address()函数的返回值结合(*caller) 命令: addr2line -f -e ./程序名 -a 返回值(caller) 查看内存泄露的程序及具体行数。

#define _GNU_SOURCE
#include <dlfcn.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <link.h>

//方式二:hook

// gcc -o memleak memleak.c -g -ldl
// addr2line -f -e ./memleak -a 0x400b38(返回值)

typedef void *(*malloc_t)(size_t size);
malloc_t malloc_f = NULL;

typedef void (*free_t)(void *ptr);
free_t free_f = NULL;


int enable_malloc_hook = 1;
int enable_free_hook = 1;

void *COnvertToELF(void *addr) {
	Dl_info info;
	struct link_map *link;

	dladdr1(addr, &info, (void**)&link,RTLD_DL_LINKMAP);

	return (void*)((size_t)addr - link->l_addr);
}

void *malloc(size_t size) {

	void *ptr = NULL;
	if (enable_malloc_hook) {
		enable_malloc_hook = 0;
	
		ptr = malloc_f(size);

	// main --> f1() --> f2() --> f3() { __builtin_return_address(0)  }

		void *caller = __builtin_return_address(0);

		char filename[128] = {0};
		sprintf(filename, "./mem/%p.mem", ptr);

		FILE *fp = fopen(filename, "w");
		fprintf(fp, "[+] caller: %p, addr: %p, size: %ld\n",
			 COnvertToELF(caller), ptr, size);


		fflush(fp);
		
		enable_malloc_hook = 1;
	} else {
		ptr = malloc_f(size);
	}
	
	return ptr;
}

void free(void *ptr) {

	if (enable_free_hook) {
		enable_free_hook = 0;
        
        char file[128] = {0};
		sprintf(file, "./mem/%p.mem", ptr);

		if (unlink(file) < 0) { // filename no exist;
			printf("double free: %p\n", ptr);
			return ;
		}

		free_f(ptr);

		enable_free_hook = 1;
	} else {

		free_f(ptr);
		
	}

}


void init_hook(void) {

	if (!malloc_f) {
		malloc_f = dlsym(RTLD_NEXT, "malloc");
	}
	if (!free_f) {
		free_f = dlsym(RTLD_NEXT, "free");
	}
}



int main(void) {

    init_hook();

    void *p1 = malloc(8);
    void *p2 = malloc(16);
    void *p3 = malloc(32);

    free(p1);
    free(p2);

    return 0;
}

编译执行:

 表示在memleak.c 文件的 main 函数中, 第149行出现内存泄漏问题。

源文件 memleak.c 


#define _GNU_SOURCE
#include <dlfcn.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <link.h>


// 方式一:宏定义
#if 0

void *_malloc(size_t size, char *filename,int line) {

    void *ptr = malloc(size);
    
    char file[128] = {0};
    sprintf(file ,"./mem/%p.mem" ,ptr);
    FILE *fp = fopen(file ,"w");//w小写

    fprintf(fp, "[+]addr: %p filename: %s line: %d\n",ptr,filename,line);

    fflush(fp);
    fclose(fp);

    return ptr;
}

void _free(void *ptr, char *filename,int line) {

    char file[128] = {0};
    sprintf(file,"./mem/%p.mem",ptr);

    if(unlink(file) < 0){//unlink用于在文件系统中删除指定的文件
        printf("double free %p\n",ptr);
        return;
    }

    return free(ptr);

}

// __FILE__ 获取文件名
// __LINE__ 获取函数执行的行号

#define malloc(size)   _malloc(size, __FILE__,__LINE__)
#define free(ptr)      _free(ptr, __FILE__,__LINE__)

//方式二:hook
#elif 1
// gcc -o memleak memleak.c -g -ldl
// addr2line -f -e ./memleak -a 0x400b38

typedef void *(*malloc_t)(size_t size);
malloc_t malloc_f = NULL;

typedef void (*free_t)(void *ptr);
free_t free_f = NULL;


int enable_malloc_hook = 1;
int enable_free_hook = 1;

void *COnvertToELF(void *addr) {
	Dl_info info;
	struct link_map *link;

	dladdr1(addr, &info, (void**)&link,RTLD_DL_LINKMAP);

	return (void*)((size_t)addr - link->l_addr);
}

void *malloc(size_t size) {

	void *ptr = NULL;
	if (enable_malloc_hook) {
		enable_malloc_hook = 0;
	
		ptr = malloc_f(size);

	// main --> f1() --> f2() --> f3() { __builtin_return_address(0)  }

		void *caller = __builtin_return_address(0);

		char filename[128] = {0};
		sprintf(filename, "./mem/%p.mem", ptr);

		FILE *fp = fopen(filename, "w");
		fprintf(fp, "[+] caller: %p, addr: %p, size: %ld\n",
			 COnvertToELF(caller), ptr, size);


		fflush(fp);
		
		enable_malloc_hook = 1;
	} else {
		ptr = malloc_f(size);
	}
	
	return ptr;
}

void free(void *ptr) {

	if (enable_free_hook) {
		enable_free_hook = 0;
        
        char file[128] = {0};
		sprintf(file, "./mem/%p.mem", ptr);

		if (unlink(file) < 0) { // filename no exist;
			printf("double free: %p\n", ptr);
			return ;
		}

		free_f(ptr);

		enable_free_hook = 1;
	} else {

		free_f(ptr);
		
	}

}


void init_hook(void) {

	if (!malloc_f) {
		malloc_f = dlsym(RTLD_NEXT, "malloc");
	}
	if (!free_f) {
		free_f = dlsym(RTLD_NEXT, "free");
	}
}


#endif

#if 1
int main(void) {

    init_hook();

    void *p1 = malloc(8);
    void *p2 = malloc(16);
    void *p3 = malloc(32);

    free(p1);
    free(p2);

    return 0;
}

#endif

注意:提前在程序目录下创建mem文件夹,编译时添加 -g -ldl

具体使用时只需将该文件的main函数注释掉,与需要检测的程序源文件一起编译执行即可。 

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

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

相关文章

LaTeX 公式与表格绘制技巧

LaTeX 公式与绘图技巧公式基本可以分为 单一公式单一编号单一公式按行编号单一公式多个子编号单一公式部分子编号分段公式现在给出各自的代码单一公式单一编号 公式1&#xff1a;equationaligned\begin{equation}\begin{aligned}a&bc\\b&a2\\c&b-3\end{aligned}\en…

Windows terminal美化工具Oh-My-Posh

1、前言 windows电脑上的终端工具Window terminal大家应该都不陌生&#xff0c;这里介绍一款美化工具&#xff0c;从此告别windows terminal的黑与白。 2、Oh-My-Posh Oh My Posh 是一个命令行提示工具&#xff0c;通常用于美化和自定义终端提示符。它允许用户创建自定义的终…

Windows:Arduino IDE 开发环境配置【保姆级】

参考官网&#xff1a;Arduino - Home Arduino是一款简单易学且功能丰富的开源平台&#xff0c;包含硬件部分&#xff08;各种型号的Arduino开发板&#xff09;和软件部分&#xff08;Arduino IDE)以及广大爱好者和专业人员共同搭建和维护的互联网社区和资源。 Arduino IDE软件…

【玩机】如何修改iPhone充电提示音!最详细简单保姆级教程~ 学费了可替换任意音频做你的专属充电提示音!——后厂村路灯

其实方法很简单&#xff0c;利用快捷指令&#xff0c;获得base64 位的音频文本&#xff0c;然后再充电时播放即可。 视频教程 【玩机】如何修改iPhone充电提示音&#xff01;最详细简单保姆级教程 具体操作如下&#xff1a; 1.首先&#xff0c;网上找到需要设定的音频&#xf…

深度学习中的一些概念

回归问题 在深度学习中&#xff0c;回归问题是一种机器学习任务&#xff0c;其目标是预测连续数值的输出。与分类问题不同&#xff0c;其中目标是将输入数据分为不同的类别&#xff0c;回归问题的目标是根据输入数据来预测一个连续的数值。回归问题通常涉及到建立一个数学模型…

mysql面试题53:一个6亿的表a,一个3亿的表b,通过外间tid关联,你如何最快的查询出满足条件的第50000到第50200中的这200条数据记录

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:一个6亿的表a,一个3亿的表b,通过外间tid关联,你如何最快的查询出满足条件的第50000到第50200中的这200条数据记录 可以按照以下步骤进行: 确保…

rust: function

///file: nestd.rs ///ide: RustRover 233.8264.22 /// /// /// /***自定义函数*/ pub fn function() {println!("called my::nested::function()"); }#[allow(dead_code)] fn private_function() {println!("called my::nested::private_function()"); }/…

vue-rouer 路由

安装/配置: //进入项目目录:(在搭建项目的时候安装了) cnpm install vue-router --save旧版路由 需要自己配置 //项目中载入,一般在main.js中载入:import VueRouter from vue-routerVue.use(VueRouter)let router new VueRouter({}) //其中配置路径和地址//在Vue中引入:n…

YB4058是一款经济高效、完全集成的高输入电压单电池锂离子电池充电器

高输入电压充电器支持I2C和OVP保护 概述&#xff1a; YB4058是一款经济高效、完全集成的高输入电压单电池锂离子电池充电器。充电器使用了锂离子电池所需的CC/CV充电曲线。充电器可接受高达27V的输入电压&#xff0c;但当输入电压超过OVP时禁用阈值&#xff0c;通常为6.8V&am…

【神印王座】悲啸洞穴中隐藏的人有多强?实力不如魔神皇,靠一绝招魔神皇都怕

Hello,小伙伴们&#xff0c;我是小郑继续为大家深度解析国漫资讯。 神印王座动漫现在已经更到龙皓晨等人深入魔族地界抵达悲啸洞穴的阶段。而刚到悲啸洞穴龙皓晨等人就被悲啸声所阻&#xff0c;龙皓晨生怕队友进入其中后有人会死亡&#xff0c;所以决定自己一个人进去探索。而小…

树模型(2)随机森林

随机森林属于集成学习中bagging算法的延展&#xff0c;所以先来介绍一下集成学习。 **集成学习&#xff1a;**对于训练数据集&#xff0c;我们通过训练一系列个体学习器&#xff0c;并通过一定的结合策略将它们组合起来&#xff0c;形成一个强有力的学习器 **个体学习器&…

cartographer中的扫描匹配

cartographer中的扫描匹配 cartographer中使用了两种扫描匹配方法&#xff1a;CSM&#xff08;相关性扫描匹配方法&#xff08;暴力匹配&#xff09;&#xff09;、ceres优化匹配方法 CSM可以简单地理解为暴力搜索&#xff0c;即每一个激光数据与子图里的每一个位姿进行匹配&…

数据结构和算法——树结构

又叫二叉排序树。 满二叉树&#xff1a;所有的叶子节点都在最后一层。 完全二叉树&#xff1a;如果所有叶子节点都在最后一层和倒数第二层&#xff0c;而且每个叶子节点都有左右子节点。 完全二叉树 前序遍历 1、先输出当前节点&#xff08;初始是root节点&#xff09;。 2、…

论文阅读:Image-to-Lidar Self-Supervised Distillation for Autonomous Driving Data

目录 摘要 Motivation 整体架构流程 技术细节 雷达和图像数据的同步 小结 论文地址: [2203.16258] Image-to-Lidar Self-Supervised Distillation for Autonomous Driving Data (arxiv.org) 论文代码&#xff1a;GitHub - valeoai/SLidR: Official PyTorch implementati…

股票买卖问题I、II、III、IV、V、VI

力控121、122、123、188、714、309。 买卖股票的第一题 121. 买卖股票的最佳时机 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设…

tomcat部署jenkins

tomcat部署jenkins 1.简介&#xff1a; Jenkins是一个开源的自动化服务器工具&#xff0c;用于持续集成和持续交付。它能够自动化构建、测试和部署软件项目&#xff0c;提高开发团队的效率和软件质量。 jenkins就是一个整合工具&#xff0c;把代码从git或者其他代码托管平台…

windows10 sockect tcp

1. 在vs下添加ws2_32.lib库 右键【项目】-【属性】-【链接器】-【输入】-【附加依赖项】&#xff0c;进行编辑&#xff0c;添加 ws2_32.lib库&#xff0c;去掉从父级或项目默认设置继承的勾选&#xff0c;如下图所示&#xff1a; 这是因为inet_addr是一个老函数&#xff0c;而…

【MySQL】索引的作用及知识储备

为什么要有索引 索引可以提高数据库的性能。不用加内存&#xff0c;不用改程序&#xff0c;不用调sql&#xff0c;只要执行正确的create indix&#xff0c;查询的速度就可能提高成百上千倍。但相应的代价是&#xff0c;插入&#xff0c;更新&#xff0c;删除的速度有所减弱。 …

【重新定义matlab强大系列十六】求解混合整数线性问题

&#x1f517; 运行环境&#xff1a;Matlab &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 #### 防伪水印——左手の明天 #### &#x1f497; 大家好&#x1f917;&#x1f91…

【算法|动态规划No.18】leetcode718. 最长重复子数组

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…