内存问题的检查

问题

最近在查程序的内存问题,包括前一篇文章也是与此相关《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

时间: 2024-08-29 08:41:05

内存问题的检查的相关文章

Analyze(内存泄漏的检查)

怎么保证多人开发进行内存泄漏的检查: 1,使用Analyze进行代码的静态分析. 在非ARC下, 2,为避免不必要的麻烦多人开发时尽量使用ARC.

c++ 内存泄露的检查

对于c++的内存泄露检测,除了我们自己手动检查以外,还可以使用c++中的函数来帮助我们检测, 如下代码: #include "stdafx.h" #include <string> #include<iostream> #include <crtdbg.h> using namespace std; int main() { char *p=new char[10]; //char *pp=new char[100]; delete p; _CrtD

Android —— 内存泄漏检查

今天地铁上看到一篇不错的将内存泄漏简单检查的文章,觉得还不错哟,内存泄漏确实是每个程序员头疼的事情,这里就多研究一下咯^^ 一. 常见的垃圾回收算法 参看文章 引用计数法 引用计数法基本上最简单的垃圾回收策略,它的核心思想是: 当有指针指向某实例时,计数加一, 当删除一个指针时,计数减一,当计数为0时,说明该实例没有引用可以被垃圾回收器回收. 这种回收策略的缺点是显而易见的: 1.维护引用计数是有开销的 2.计数的保存会消耗额外的空间 3.无法处理循环引用 标记清除 标记清除,顾名思义分为2步:

对象与运行时内存

和大多数猴子一样,我原来也抵触对原理的学习, 后来发现掌握了原理才有了那种了然于胸,运筹帷幄的感觉,也就是顿悟. 这里主要介绍Java对象与运行时内存的知识. java运行时内存 Program Counter Registe(程序计数器): 记录当前线程执行字节码的位置,相当于行号指示器,为线程私有的. Java Virtual Machine Stacks(java虚拟机栈): 存放方法出口信息.局部变量表(对象引用.基本类型数据等),为线程私有的. Native Method Stack(

Windows系统内存分析工具的介绍

? Windows系统内存分析工具的介绍(进程管理器,资源管理器,性能监视器, VMMap, RamMap,PoolMon) 微软官方提供多种工具来分析Windows 的内存使用情况,除了系统自带的任务管理器(Task Manager), 资源监视器(Resource Manager), 性能监视器(Performance Monitor), 还有SysInternals工具, ?RamMap, PoolMon用以分析内存问题.本文简单介绍上述工具的快速使用方法,如果需要了解深入了解,请参考微软

Cgroup - Linux 内存资源管理

Hi ,我是 Zorro .这是我的微博地址,我会不定期在这里更新文章,如果你有兴趣,可以来关注我呦. 另外,我的其他联系方式: Email: [email protected] QQ: 30007147 本文PDF 在聊 cgroup 的内存限制之前,我们有必要先来讲解一下: Linux 内存管理基础知识 free 命令 无论从任何角度看, Linux 的内存管理都是一坨麻烦的事情,当然我们也可以用一堆.一片.一块.一筐来形容这个事情,但是毫无疑问,用一坨来形容它简直恰当无比.在理解它之前,我

iOS面试题05-父子控制器、内存管理

内存管理.父子控制器面试题 1.建立父子关系控制器有什么用 回答:1>监听屏幕选中 2>如果想拿到你当前的很小的一个控制器所在的导航控制器必须要跟外面比较大的控制器建立父子关系,才能一层一层往上拿导航控制器 2.第三方API是怎么用的? 回答:0>大公司的开放API 1>github上面别人发布的框架 2>第三方API在官方文档都有说明,按照官方文档一步一步做 3>参考官方提供的示例程序 4>先自己创建一个工程试试,等熟悉了,在使用到项目中 3.列举现在熟悉iOS

内存管理机制剖析

在.NET Framework中,内存中的资源(即所有二进制信息的集合)分为"托管资源"和"非托管资源".托管资源必须接受.NET Framework的CLR(通用语言运行时)的管理(诸如内存类型安全性检查),而非托管资源则不必接受.NET Framework的CLR管理.  (了解更多区别请参阅.NET Framework或C#的高级编程资料) 托管资源在.NET Framework中又分别存放在两种地方: "堆栈"和"托管堆&quo

菜鸟nginx源码剖析数据结构篇(九) 内存池ngx_pool_t[转]

菜鸟nginx源码剖析数据结构篇(九) 内存池ngx_pool_t Author:Echo Chen(陈斌) Email:[email protected] Blog:Blog.csdn.net/chen19870707 Date:Nov 11th, 2014 今天是一年一度的光棍节,还没有女朋友的程序猿童鞋不妨new一个出来,内存管理一直是C/C++中最棘手的部分,远不止new/delete.malloc/free这么简单.随着代码量的递增,程序结构复杂度的提高.今天我们就一起研究一下以精巧著