首页 > 使用valgrind检测ATS插件中的内存泄露

使用valgrind检测ATS插件中的内存泄露

一.内存错误出现的场景

这几天在重构ATS插件代码的过程中遇到了烦人的内存泄露问题, 周五周六连续两天通过走查代码的方法,未能看出明显的导致内存错误的代码, 同时也觉得C和C++混合编程得到一个动态库, 在一个.cpp主文件中,即用new又用malloc来动态分配内存, 可能会导致内存错误.后来网上调研和查资料发现, new和malloc混用还是允许的,因为C++兼容C.虽然这种混用方式不提倡, 但绝对不会导致内存堆栈错乱的情况.

这里之所以采用C和C++混合编程,是因为业务需要. ATS插件目前设计为一个transform主框架, 外加若干子模块, 一个子模块一个动态库,后者可以根据不同业务需要进行扩展,而transform类型的插件框架一般不变, 它只完成通常的transform变换流程就可以了. 这个主框架是使用C++开发的, 它提供了业务实现接口, 供每个业务动态库实现.因为接口入参中用到了stl的map结构来在主框架和子模块之间传递参数,所以接口的实现必须是C++方式的. 但是我的一个业务插件原来是使用纯c编写的, 引用了几个第三方库,比如JSON, libz, pcre库等, 它们原来已经用C编写好了,并且经过测试发现是可靠的, 如果再换为C++实现一般不太现实, 也没有必要. 这样造成的局面就是, 目前只能C和C++进行混合编程, 对C提供的接口, 要在h文件中使用 extern "C"声明, 并将实现存放在对应的c文件中.(这里必须要分离成两个文件, 如果以前只有一个h文件就搞定的, 现在要分为h和c文件).在编译出一个so时, 同时要外链其他的第三方基础库时, Makefile的编写通常有些技巧的, 请参见我的博文

C和C++混合编程的Makefile的编写!

这种情况下, 对C那部分的调用,我采用malloc和free来分配和释放内存, 对上层接口那部分, 我在主cpp文件中使用new和delete来分配内存.这里明显使得内存的使用更加复杂化了,但是不管怎样,按理说这种做法还是行得通的.

但是在调试过程中,我却发现了一个内存越界的错误, 每次提示的错误都不一样, 但是显示出错的位置又没有明显的错误, 真是让人摸不到头脑, 搞不定了, 郁闷, 失败至极.....

二.内存错误出现的表象

两天的搜索无果, 让我只能寻求内存检测软件的帮助. 我以前用过tcmalloc, 就是google的gperftools里面的一个工具,它会将系统默认的内存分配释放函数替换为自己的函数再进行检测,但是在这里不方便施展, 因为这里new和malloc都用上了, 所以我决定使用valgrind来检测. 具体安装使用方法,请参见

在Ubuntu 14.04 64bit上安装Valgrind并检查内存泄露

下面是ATS插件运行中崩溃时valgrind检测的几个错误截图



该截图告诉我们, pool_alloc(在mem_manage.c第17行)调用malloc分配了1813字节内存, find_replace_html(位于main.cpp第484行)函数使用memcpy从1808处开始要复制8个字节, 而事实上只能复制4字节,这会内存越界,导致非法的8字节写入(越界写入).



该截图告诉我们,  pool_alloc(在mem_manage.c第17行)调用malloc分配了1813字节内存,pcre_exec(在 regex_lookup.h第45行)在1813字节后面越界读取了1个字节.



该截图告诉我们, 在分配的1813字节内部的1808字节处, 要非法读取8字节内存(越界读取)

三.内存错误的分析和确定

上面的截图分析, 很明确地传递出内存越界读取和越界写入的错误, 但是我查看内存分配的地方, 没有看到明显的错误.但是多次调试显示的内存错误大多显示到memset这样的地方, 将部分memset代码注释掉后, 程序能运行, 但是运行一段时间后,它还是会有段错误, 看来找到的位置不对, 而且上面截图显示的都是造成错误的表现, 不是真正造成内存出错的地方.最后经过认真理解valgrind的错误提示, 和仔细地分析代码, 终于定位到内存错误的真正地方不是malloc长度那里, 而是memset那里, 初始化内存的那个指针只能是一个void*或char*, 不能是一个结构体, 这就是内存错误的真正地方.

参见下面的截图, 有内存错误的源码截图



改正内存错误的源码截图



改正后, 重新编译调试, 一切正常, 运行很长时间, 都没有再崩掉, 再次印证修改是正确的.而这个错误, 是一个大家看起来很可笑的问题, 所要大家编写代码时还是要提高修养和注意力,千万不要马虎写代码,否则会害死自己的.

四.回顾反思

bug不可怕, 犯错不可耻, 但是仔细分析导致bug的原因, 吸取教训并避免再犯才是最重要的. 另外一点是, 排错的锻炼和快速定位是一项职业素养, 越修bug越有收获越能提高, 经历越丰富自信心越强, 所以bug来了,我们还是得从容面对.

更多相关:

  • 更多内容,欢迎关注微信公众号:全菜工程师小辉~前言在笔者上一篇博客,详解了NIO,并总结NIO相比BIO的效率要高的三个原因,彻底搞懂NIO效率高的原理。这篇博客将针对第三个原因,进行更详细的讲解。首先澄清,零拷贝与内存直接映射并不是Java中独有的概念,并且这两个技术并不是等价的。零拷贝零拷贝是指避免在用户态(User-space)...

  • 一、预备知识—程序的内存分配  一个由c/C++编译的程序占用的内存分为以下几个部分  1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈,如果还不清楚,那么就把它想成数组,它的内存分配是连续分配的,即,所分配的内存是在一块连续的内存区域内.当我们声明变量时,那么编译器...

  • 我的爱机是一台ThinkPad T420,原装三星DDR 1333 4G内存一根,还剩一根内存位置,最近趁京东6.18促销,准备增加一根物理内存。为了确保兼容性,觉得仍然选购DDR 1333 4G内存,于是购买了金士顿这款,比如DDR3 1600的还贵。 这个安装过程完全参照该内存的网页提示进行 这里简单记录一下,以备...

  • 陪伴我多年的老本ThinkPad T420渐渐垂垂老矣, 我想更新一下可以更新的部分, 比如将2.5寸HDD更换为SSD, 将单条4G内存再增加一根, 凡此种种想法, 可能最后归结为如何获取该笔记本的硬件配置信息, 在windows下面使用鲁大师之类的检测软件, 也许很好搞定,但是在Ubuntu 14.04平台上如果办到呢? 很简单...

  • 1. Go 的错误机制 Go 语言的错误机制中与其他语言的主要差异如下: 没有异常机制error 类型实现了 error接口type error interface {Error() string } 可以通过errors.New来快速创建错误实例errors.New(" num is not in range[0,100]")...

  • 能够在Linux系统下体验到原生界面的网易云音乐是件不错的事情,但是它总是经常性的出现网络异常,界面无响应的问题 为了听歌的体验,进行深入探究: 首先通过终端启用网易云音乐:sudo netease-cloud-music 会得到网易云音乐运行时的信息,比如一些出错的信息 其实我已经解决了首要的问题(QSslSocket错误),因...

  • 【错误页面处理】 訪问一个错误的控制器 訪问一个错误的方法 有些控制器和方法禁止訪问   以上訪问会提示错误信息 404  403 以上错误信息是不方便给外边用户看到的。 1. 安全隐患 2. 用户体验不好 错误信息在site/error这个地方定义的。   如今我们要自己定义错误页面来显示我们的错误信息 转载于:...

  • 噪声的来源: 1、noise in y 2、noise in x 在有noise的情况下,vc bound还会work么??? 之前,x ~ p(x)  现在 y ~ P( y | x ) 在hoeffding的部分,只要 (x, y) 联合分布满足某个分布, 结果是一致的。   error measure:打分衡量f和g的距离 1、...

  • 在IIS7.5打开网页的时候,提示: HTTP 错误 500.0 - Internal Server Error 调用 LoadLibraryEx 失败,在 ISAPI 筛选器 C:WindowsMicrosoft.NETFrameworkv4.0.30319\aspnet_filter.dll,经过排除发现原来是两个斜杠导...

  • 原文出处: 韩昊    1 2 3 4 5 6 7 8 9 10 作 者:韩 昊 知 乎:Heinrich 微 博:@花生油工人 知乎专栏:与时间无关的故事   谨以此文献给大连海事大学的吴楠老师,柳晓鸣老师,王新年老师以及张晶泊老师。   转载的同学请保留上面这句话,谢谢。如果还能保留文章来源就更感激不尽了。 我保证这篇文章...

  • 原文出处: 韩昊   我保证这篇文章和你以前看过的所有文章都不同,这是 2012 年还在果壳的时候写的,但是当时没有来得及写完就出国了……于是拖了两年,嗯,我是拖延症患者…… 这篇文章的核心思想就是: 要让读者在不看任何数学公式的情况下理解傅里叶分析。 傅里叶分析不仅仅是一个数学工具,更是一种可以彻底颠覆一个人以前世界观的思维...

  • 很多Linux高手都喜欢使用screen命令,screen命令可以使你轻松地使用一个终端控制其他终端。尽管screen本身是一个非常有用的工具,byobu作为screen的增强版本,比screen更加好用而且美观,并且提供有用的信息和快捷的热键。 想象一下这样一个场景:你通过Secure Shell(ssh)链接到一个服务器,并...

  • NarrowbandPrimary Synchronization Signal时域位置每1个SFN存在一个NPSSSFNSubframeSymbol长度每个SFN5最后11个symbol11个symbols频域位置NB-IOT下行带宽固定180kHz,一个PRB,12个子载波。...

  •  [h1]反斜杠只能够阻止一个字符  [h2]位于键盘的左上角,和~公用一个键。...