首页 > 代码库 > 内存问题的检查

内存问题的检查

问题

最近在查程序的内存问题,包括前一篇文章也是与此相关《snprintf/_snprintf 在不同平台间函数差异》。
先看一段简单的程序:

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
end

为何循环4次只输出一次呢?使用gdb查看,发现由于memcpy越界,直接把变量“i”改成了一个极大的值。所以一次就结束了。
这段程序极为凶险的是memcpy越界编译没有报错,执行没有core dump(如果将数组b改为超大如1000等就可能会dump),而是结果错误。设想一下,如果memcpy改了别的什么内存位置的值,程序如何执行就进入了一个未知的情况,再加上多线程等复杂的业务场景,就是一颗定时炸弹,平时好好的,而不知何时,就“啵”的爆炸了。而这种情况查看犯罪现场的core文件,使用bt得到的已经不是真正问题的所在,而是由于之前的内存越界导致的正常代码留下的尸体。

在复杂的业务逻辑中使用memcpy、strcmp等这种较为底层的函数,本身就是自讨苦吃。代码量大,开发难度大,一般人写出的代码质量不高,出了问题不好查……所以难怪从java到python、php等大行其道。

如何避免

  1. RAII
  2. 尽量避免在C++中使用原生数组,以及相关的操作,如memcpy、memset、strcpy等
  3. 使用string、vector等STL来替代。还可以研究一下auto_ptr等职能指针来减少错误~。

出现了怎么查

  1. 当然还是人肉看代码。
  2. 使用工具。cppcheck、Valgrind等来查。

工具用法

  1. 使用Valgrind
    动态工具,只支持linux系列,不支持windows。参见《应用 Valgrind 发现 Linux 程序的内存问题》。
    实测发现memcpy拷贝的内容长度超过了目的数组的长度时,Valgrind检查不出来。
    使用方便,直接 valgrind [args] program program_args

  2. 使用cppcheck
    静态检查工具。支持linux、windows。
    实测发现可以发现memcpy拷贝的内容长度超过了目的数组的长度溢出问题。
    使用也很方便,cppcheck xxx.cpp

这两个工具要配合使用。

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

内存问题的检查