#问题 最近在查程序的内存问题,包括前一篇文章也是与此相关《snprintf/_snprintf 在不一样平台间函数差别》。 先看一段简单的程序:php
<!-- lang: cpp --> int main() { for(int i=0; i<5; i++) { char k[4]; char *p = k; char b[] = "123456789"; memcpy(p, b, sizeof(b)); cout << "in loop" << endl; } cout << "end" << endl; return 0; }
输出以下: in loop endhtml
为什么循环4次只输出一次呢?使用gdb查看,发现因为memcpy越界,直接把变量“i”改为了一个极大的值。因此一次就结束了。 这段程序极为凶险的是memcpy越界编译没有报错,执行没有core dump(若是将数组b改成超大如1000等就可能会dump),而是结果错误。设想一下,若是memcpy改了别的什么内存位置的值,程序如何执行就进入了一个未知的状况,再加上多线程等复杂的业务场景,就是一颗定时炸弹,平时好好的,而不知什么时候,就“啵”的爆炸了。而这种状况查看犯罪现场的core文件,使用bt获得的已经不是真正问题的所在,而是因为以前的内存越界致使的正常代码留下的尸体。java
在复杂的业务逻辑中使用memcpy、strcmp等这种较为底层的函数,自己就是自讨苦吃。代码量大,开发难度大,通常人写出的代码质量不高,出了问题很差查……因此难怪从java到python、php等大行其道。python
使用Valgrind 动态工具,只支持linux系列,不支持windows。参见《应用 Valgrind 发现 Linux 程序的内存问题》。 实测发现memcpy拷贝的内容长度超过了目的数组的长度时,Valgrind检查不出来。 使用方便,直接 valgrind [args] program program_argslinux
使用cppcheck 静态检查工具。支持linux、windows。 实测发现能够发现memcpy拷贝的内容长度超过了目的数组的长度溢出问题。 使用也很方便,cppcheck xxx.cppwindows
这两个工具要配合使用。数组
ps:cppcheck默认安装会报错以下:多线程
(information) Failed to load std.cfg. Your Cppcheck installation is broken, please re-install. The Cppcheck binary was compiled without CFGDIR set. Either the std.cfg should be available in cfg or the CFGDIR should be configured.函数
解决方法: cppcheck的linux安装须要在make时候对参数CFGDIR配置,设置为绝对路径,如:make CFGDIR=/usr/bin/cfg 安装时候也带上此参数:make install CFGDIR=/usr/bin/cfg工具