Linux C/C++ 内存泄漏检测

2023-05-16

文章目录

  • 原理
    • 内存泄漏概念
    • 检测原理
  • 实现方式
    • 重载
    • gcc_wrap
    • LD_PRELOAD偷梁换柱

原理

内存泄漏概念

内存泄漏(Memory leak):在计算机科学中,由于疏忽或错误造成程序未能释放已经不再使用的内存被称之为内存泄漏。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在导致程序未被释放,从而造成了内存的浪费。

在这里插入图片描述

检测原理

要想实现内存泄漏检测,最容易想到的就是在程序对内存进行操作(eg: 申请内存释放内存 等)时记录下来,程序退出时对照一下申请和释放是否对应得上,即可实现内存泄漏检测。说起来并不难,但是我们如何监听程序对内存的操作呢?这个会在下面的具体方式里讲到。

那么延伸一下,如何检测 野指针

在这里插入图片描述
根据我浅薄的认知,目前仅知道可使用 内存涂鸦 的方式,即每次申请内存,先对其内容进行未初始化涂鸦。若使用该指针时发现其指向为未初始化涂鸦值,则证明该指针为 野指针

同理,我们释放内存也需对其进行内存涂鸦,这样再次调用该指针时,发现其指向内存被涂鸦成 未初始化,即可知其使用的是野指针。

据我所知有些编译器就是这么做的,例如 VC++

实现方式

上面的原理听起来不难,但是具体怎么记录某程序的内存操作呢?

较为简便的是以下三种方法:

重载

当我们在程序中写下 newdelete 时,我们实际上调用的是 C++ 语言内置的 new operatordelete operator。所以我们可以重载其 new operatordelete operator 以实现内存分配及释放情况的记录与分析。

这种方法,在之前的博文:C++ -重载运算符 实现数组越界检测&被除数检测 里讲过,这里仅告知需要重写以下函数:

void* operator new( size_t nSize, char* pszFileName, int nLineNum )
void* operator new[]( size_t nSize, char* pszFileName, int nLineNum )
void operator delete( void *ptr )
void operator delete[]( void *ptr )

该方法的缺点也是很明显的,它只是相当于给库函数再封装了一层。在这一层内实现了对内存的记录分析。

对于原有项目(直接使用 new operator & delete operator 等),需要将 new( )delete( ) 等 一.一 修改,方可实现内存检测。
在这里插入图片描述

gcc_wrap

山重水尽疑无路 柳暗花明又一村

GCC 为我们预留了后门,给我们留下了一个有趣的选项 –wrap=symbol

我们可称之为 包装函数;它可以使链接器在链接 symbol符号 时优先查找__wrap_symbol,查找不到时才会链接原始的 symbol符号

下面是一个 demo

/* test.cpp */
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>

extern "C"
{
	int malloc_count = 0;
	int free_count = 0;

	void *__real_malloc(size_t size);
	void __real_free(void *ptr);
	void print_trace ();

	void *__wrap_malloc(size_t size){
		malloc_count++;
		print_trace();
		return __real_malloc(size);
	}
	void __wrap_free(void *ptr){
		free_count++;
		print_trace();
		__real_free(ptr);
	}

	void *operator new(size_t size){
		return __wrap_malloc(size);
	}

	void operator delete(void *ptr){
		__wrap_free(ptr);
	}

	void print_trace () 
	{
		printf ("========== call stack =========\n");
		void *array[10];
		int size; 
		char **strings; 
		int i;
		size = backtrace (array, 10);
		strings = backtrace_symbols (array, size);
		if (NULL != strings)
		{
			printf ("Obtained %zd stack frames.\n", size);
			for (i = 0; i < size; i++)
			{
				printf ("%s\n", strings[i]);
			}
			__real_free(strings); 
			strings = NULL; 
		}
	}
}

int main(){

	int *p1 = (int*)malloc((sizeof(int)));
	int *ptr1 = new int[5];
	int *ptr2 = new int[5];
	delete ptr1;

	printf ("========== memory leak detection =========\n");

	printf("malloc_count = %d\n",malloc_count);
	printf("free_count = %d\n",free_count);

	if(malloc_count != free_count){
		printf("memony leak!\n");
	}

	return 0;
}

print_trace( ) 打印栈,不用亦可

编译时记得带上那个有趣的选项

gcc test.cpp -Wl,--wrap=malloc --wrap=free

LD_PRELOAD偷梁换柱

总觉得利用 gcc-wrap 的方法还不够方便,能不能打包为 so库,对任意需要内存检测的函数进行链接编译呢?

在这里插入图片描述
可达鸭表示:可

在此之前,我们先来看下 Linux系统 加载 so库 的流程:

以下内容转自 郑瀚Andrew_Hann - Linux System Calls Hooking Method Summary

包括 Linux 系统在内的很多开源系统都是基于 Glibc 的,动态链接的 ELF可执行文件 在启动时同时会启动 动态链接器(/lib/ld-linux.so.X),程序所依赖的共享对象全部由动态链接器负责 装载和初始化,所以这里所谓的共享库的查找过程,本质上就是动态链接器(/lib/ld-linux.so.X)对共享库路径的搜索过程,搜索过程如下:

  • /etc/ld.so.cacheLinux 为了加速 LD_PRELOAD 的搜索过程,在系统中建立了一个 ldconfig程序,这个程序负责:
    • 将共享库下的各个共享库维护一个 SO-NAME(一一对应的符号链接),这样每个共享库的SO-NAME就能够指向正确的共享库文件
    • 将全部SO-NAME收集起来,集中放到 /etc/ld.so.cache文件里面,并建立一个SO-NAME的缓存
    • 当动态链接器要查找共享库时,它可以直接从/etc/ld.so.cache里面查找。所以,如果我们在系统指定的共享库目录下添加、删除或更新任何一个共享库,或者我们更改了 /etc/ld.so.conf/etc/ld.preload 的配置,都应该运行一次 ldconfig 这个程序,以便更新SO-NAME和/etc/ld.so.cache
  • 根据/etc/ld.so.preload中的配置进行搜索(LD_PRELOAD):这个配置文件中保存了需要搜索的共享库路径,Linux动态共享库加载器根据顺序进行 逐行广度搜索
  • 根据环境变量LD_LIBRARY_PATH指定的动态库搜索路径
  • 根据ELF文件中的配置信息:任何一个动态链接的模块所依赖的模块路径保存在 ".dynamic"段 中,由 DT_NEED 类型的项表示,动态链接器会按照这个路径去查找DT_RPATH 所指定的路径,编译目标代码时,可以对 gcc 加入链接参数-Wl,-rpath 指定动态库搜索路径。
    • DT_NEED段中保存的是绝对路径,则动态链接器直接按照这个路径进行直接加载
    • DT_NEED段中保存的是相对路径,动态链接器会在按照一个约定的顺序进行库文件查找下列路径
      • /lib
      • /usr/lib
      • /etc/ld.so.conf中配置指定的搜索路径

小结:可以看到,LD_PRELOADLinux系统 中启动新进程首先要 加载so 的搜索路径,所以它可以影响程序的运行时的链接(Runtime linker),它允许你定义在程序运行前"优先加载"的动态链接库。

我们只要在通过 LD_PRELOAD加载的 .so 中编写我们需要 hook 的同名函数,根据Linux对外部动态共享库的符号引入全局符号表的处理,后引入的符号会被省略,即系统原始的 .so(/lib64/libc.so.6) 中的符号会被省略。

通过 strace program 也可以看到,Linux 是优先加载 LD_PRELOAD 指明的 .so,然后再加载系统默认的 .so的。

/* testmallic.cpp*/
#include <stdio.h>
#include <stdlib.h>

int malloc_count = 0;
int free_count = 0;

void printf_end();

void printf_end(){
	fprintf(stderr,"=========Result=========\n");
	fprintf(stderr,"malloc_count = %d\n",malloc_count);
	fprintf(stderr,"free_count = %d\n",free_count);
	if(malloc_count != free_count){
		fprintf(stderr,"Memlook\n");
	}
}

void* malloc(size_t size){
	if(0 == malloc_count){
		atexit(printf_end);
	}
	malloc_count ++;
	fprintf(stderr,"malloc_count = %d\n",malloc_count);
	return realloc(NULL,size);
}

void free(void *p){
	free_count ++;
	fprintf(stderr,"free_count = %d\n",free_count);
	realloc(p,0);
}

编译为 so库

g++ -shared -fpic -o testmallox.so testmallic.cpp

再写个测试用例

/*main.cpp*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){
    char *c1 = (char*)malloc(sizeof(char));
    int *c2 = (int*)malloc(sizeof(int));
	free(c1);
	return 0;

}

编译一下
g++ -o main main.cpp

运行
LD_PRELOAD=./testmalloc.so ./main

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux C/C++ 内存泄漏检测 的相关文章

  • c语言中求数组长度(*的作用,定义指针变量与取值)

    最近在学习c语言 xff0c 在c语言中少了很多库函数 xff0c 就比如我在求数组长度的时候 xff0c len 不能用了 xff0c 这在python中是自带的函数 即使在c 43 43 中 xff0c 求字符串长度时也能用str le
  • 个人使用ubuntu18相关配置

    root登陆 1 首先获得临时的root权限 xff0c 因为后面的一些操作需要root权限才可以 xff0c 打开终端输入以下命令 sudo s 之后直接输入当前账户的密码 xff0c 就可以获得临时的root权限 2 先创建root账户
  • Manjaro内存不足解决记录

    1 Linux虚拟机 最近在家闲得没事做 xff0c 就使用VMware装了一个linux虚拟机 xff0c 虽然之前装过许多linux发行版的虚拟机 xff0c 也装过win10 43 Deepin双系统 xff0c 但是从来没具体了解过
  • String/StringBuilder/StringBuffer

    String StringBuilder StringBuffer 1 可变性 String 字符串常量 xff0c 字符串是不可变的 源码中 xff1a span class token keyword private span span
  • 计算机网络-网络结构

    计算机网络 三种网络结构 OSI xff1a 物理层 数据链路层 网络层 传输层 会话层 表示层 应用层 TCP IP xff1a 网络接口层 网际层 传输层 应用层 五层 xff1a 物理层 数据链路层 网络层 传输层 应用层 应用层 它
  • 计算机网络-三次握手/四次挥手/可靠传输/ARQ协议

    计算机网络 TCP三次握手 同步SYN 确认ACK 发送端 SYN标志的数据报 seq 61 x gt 接收端 xff08 SYN 61 1 xff09 发送端 lt SYN ACK标志的数据报 seq 61 y ack 61 x 43 1
  • 计算机网络-拥塞控制/HTTP/URL

    滑动窗口和流量控制 TCP利用滑动窗口实现流量控制 xff0c 流量控制就是为了控制发送方发送速率 xff0c 保证接收方来得及接收 接收方发送的确认报文中的窗口字段可以来控制发送方窗口大小 xff0c 从而影响发送方的发送速率 xff0c
  • Integer和int进行==比较

    Integer amp int int是Java的基本数据类型 xff0c 而Integer是它的包装类 xff0c 61 61 在进行比较时 xff0c 如果是基本类型 xff0c 比较的是值 xff0c 如果是引用类型 xff0c 比较
  • deepin恢复出厂设置_如何恢复出厂设置

    deepin恢复出厂设置 There comes a time in every user s life when they have to reset something back to its factory default Perha
  • JUC-JMM/Volatile/单例模式

    JMM Java内存模型 xff0c 是一个概念 xff0c 不存在的东西 xff0c 概念 约定 关于JMM的一些同步约定 xff1a 线程解锁前 xff0c 必须把共享变量刷回主存线程加锁前 xff0c 必须读取主存中的最新值到工作内存
  • 设计模式-六大原则/单例模式

    设计模式 概念 xff1a 是一套被反复使用 多数人知晓的 经过分类编目的 代码设计经验的总结 作用 xff1a 为了可重用代码 让代码更容易被他人理解 保证代码可靠性 程序的重用性 JDK Spring等源码中许多地方用到了设计模式 设计
  • 设计模式-工厂模式/代理模式

    工厂模式 创建对象时不会对客户端暴露创建逻辑 xff0c 并且通过使用一个共同的接口来指向新创建的对象 xff0c 实现创建者和调用者分离 xff0c 工厂模式分为简单工厂 工厂方法 抽象工厂 xff0c Spring中的IOC容器创建be
  • WSL2+VcXsrv 打开图形窗口实现可视化

    前些天有个朋友拜托我帮忙看看 老师让配置的 Cygwin 安装 gnuplot 用 XLaunch 做图形界面 始终画不出图来 这个问题我研一的时候也遇到过 走了许多弯路 所以在电脑上一阵鼓捣 现在做一个如下记录 Cygwin 43 XLa
  • gitlab 安装/卸载/备份/迁移/汉化/重置root密码 全套教程

    服务器环境 centos7 4 gitlab版本 gitlab span class token operator span ce span class token operator span 11 span class token pun
  • bash: line 5: bgzip: command not found

    报错信息 xff1a bash line 5 bgzip command not found 解决方式 xff1a conda install tabix
  • linux之chgrp命令

    chgrp 命令更改 目录或文件所属的组 chgrp R 目录 或 文件 R xff1a 递归式改变指定目录及目录下所有文件和子目录 chgrp eg chgrp group2 file2 将file2的属组更改为group2 以空格分开
  • PageHelper limit自定义位置

    package com sgcc base common rest model import com github pagehelper Page import com github pagehelper dialect helper My
  • Ubuntu20.04 执行nvidia-smi命令,显示不能连接到显卡驱动

    错误 xff1a NVIDIA SMI has failed because it couldn t communicate with the NVIDIA driver 解决这个问题的一般方法 xff1a nvidia smi 报错 xf
  • nginx安装windows服务

    进入nginx安装目录列如 D code nginx 1 6 3 将WinSW NET4 exe复制到 nginx安装目录下 将WinSW NET4 exe重名为install service exe xff0c 并创建立install s
  • 贝塞尔曲线 弯曲动画ios_用贝塞尔曲线弯曲

    贝塞尔曲线 弯曲动画ios by Nash Vail 由Nash Vail 用贝塞尔曲线弯曲 Nerding Out With Bezier Curves Since the past few days I have been trying

随机推荐

  • MySQL随机获取10条数据-多种方式

    MySQL随机获取10条数据 多种方式 测试表有 254 万条数据 xff0c 各个SQL的执行效率如下 方式一 最简单 xff0c 但是效率最低 执行时间 xff1a 9 845s SELECT FROM 96 table 96 ORDE
  • ESXI克隆虚拟主机

    目录 一 通过命令克隆主机 二 通过网页端克隆主机 一 通过命令克隆主机 1 启用esxi的ssh 2 ssh登录esxi 3 找到虚拟机所在目录 4 建立新虚拟机目录 5 拷贝vmx文件 6 克隆vmdk 7 修改vmx文件 8 esxi
  • SqlServer 查询JSON 数据

    https www cnblogs com whitebai p 13614024 html
  • 一篇文章带你发中文核心期刊《计算机科学》

    中文核心期刊 计算机科学 发论文过程分享 目录 中文核心期刊 计算机科学 发论文过程分享 1 写论文 xff0c 找杂志发表 2 寻找投稿的杂志社 xff0c 修改论文 3 论文审核流程 4 关于怎么联系杂志的编辑部 投稿的大致过程如下 x
  • unity 安装踩坑

    此贴unity安装版本为2019 1 9f1 xff0c 基本项目都是向下兼容 xff01 xff01 xff01 话不多说直接上干货 1 卸载unity hub 2 卸载unity 3 删除C ProgramData Unity文件夹 4
  • Intellij IDEA 部署Web项目后运行出现HTTP Status 404(找不到对应的路径文件,不是无法访问此网站)

    之前抽空搭建了一个java的环境做了个项目 xff0c 结果重装系统以后 xff0c 重新部署项目能够运行的时候发现了项目调试404 xff08 找不到实际的页面 xff0c 后来csdn查了一下很常见的问题 xff09 给大家推荐一下这个
  • VS 2019 使用Node.js 《环境安装》

    Vs2019安装node js 说明 1 安装node js工具 2 安装node js https nodejs org en download 3 查看环境变量是否在安装过程中自动附加 4 安装完成后重启电脑 5 运行cmd 管理员运行
  • 如何实现HTML5 Notification 桌面推送(无需域名)

    之前涉及到要做B S架构的 浏览器windows桌面的消息提醒 xff0c 然后在网上找到了Notification的消息推送 发现这类的文章挺少的 xff0c 故此写下来包装了一下方法记录一下以后用 xff0c 参考知乎大佬的文章 xff
  • .net Core MongoDB保姆级环境安装

    用户需求 xff1a 涉及多json类型的数据存储 xff0c 因redis较nosql没那么好用 xff0c 实际操作了一波环境安装 xff0c 目前我还是没有配置环境变量的 MongoDB的下载 61 官网链接 https www mo
  • mysql使用游标(优化最后一行重复的)

    纯粹是业务需要 xff0c 学习记录一下使用游标的过程 xff1b 我们先创建一张表 xff1b 假设att test是我们的表名称 xff0c 其中有两个字段 xff0c 我插入了一部分数据 xff1b 我们学习下 xff0c 如何在遍历
  • windows/linux 安装zookeeper + Kafka (含自启动)运行教学

    首先我们来花两分钟了解一下 xff1a 什么是zookeeper xff1f 什么是kafka xff1f 为什么kafka依赖zookeeper和javaSDK xff1f Zookeeper 和 Kafka 都是 Apache 软件基金
  • aws v2.2.exe_如何使用Python 3.6在AWS EC2上创建运行uWSGI,NGINX和PostgreSQLDjango服务器...

    aws v2 2 exe by Sumeet Kumar 通过Sumeet Kumar 如何使用Python 3 6在AWS EC2上创建运行uWSGI xff0c NGINX和PostgreSQLDjango服务器 How to crea
  • (ASP.NET)Gridview使用EF绑定数据库支持多个网页的增查删改

    本人新手 xff0c 在csdn根据许多博主的文章进行学习 xff0c 终于努力得到了回报 xff0c 想把这次的经验共享给大家文件我也会上传到资源里供大家参考 xff01 不喜勿喷 xff0c 有什么建议可以评论 我一定会加以学习 xff
  • Linux Debian 桌面环境

    1 问题1 E span class token operator span Could not get lock span class token operator span var span class token operator s
  • 论函数形参与实参的常见错误篇

    1 形参与实参的类型不一致引发的错误 xff0c 例子1如下 span class token macro property span class token directive keyword include span span clas
  • 目标跟踪算法综述

    前言 目标跟踪是计算机视觉领域研究的一个热点问题 xff0c 其利用视频或图像序列的上下文信息 xff0c 对目标的外观和运动信息进行建模 xff0c 从而对目标运动状态进行预测并标定目标的位置 目标跟踪算法从构建模型的角度可以分为生成式
  • 免费、稳定的天气预报API

    一 国家气象局 实时接口 xff1a 实时天气1 xff1a http www weather com cn data sk 101190408 html 实时天气2 xff1a http www weather com cn data c
  • 总结一下使用paramiko遇到的问题

    一 python报错cannot import name bcrypt 在使用import paramiko出现了这个报错cannot import name bcrypt xff0c 查了很久最终解决 查了很久发现bcrypt缺少一些文件
  • Ubuntu系统删掉自带的python如何修复

    背景 xff1a 在linux上编写pyQT相关的代码 xff0c 需要python3 6的支持 xff0c 于是把自带的python删掉 linux卸载指定python版本的方法 xff1a 1 卸载python xff08 指定相应的版
  • Linux C/C++ 内存泄漏检测

    文章目录 原理内存泄漏概念检测原理 实现方式重载gcc wrapLD PRELOAD偷梁换柱 原理 内存泄漏概念 内存泄漏 xff08 Memory leak xff09 xff1a 在计算机科学中 xff0c 由于疏忽或错误造成程序未能释