zoukankan      html  css  js  c++  java
  • Heap corruption detected.

    最近写程序忽然发现了一些错误,运行总是报Heap corruption detected. 
    断点单步发现总是在delete的时候出错。 
    以前也出现过,不过没啥注意,现在想留着是个大大的心病!于是上网查了相关资料: 
    下面是转载资料: 
    http://www.cppblog.com/kerlw/archive/2007/04/10/21604.aspx 
    今天写程序的时候到一个问题,调试的时候总是报错Heap corruption detected。一直没碰到过这样的问题,所以实在不知道如何下手。后来偶然一次注释掉一个释放语句,就没报错了Heap corruption detected了(但是报memory leak),才发现原来这个释放有问题。我的一个函数调用中,开始的时候分配了一个char数组,结束的时候释放这个数组空间,看起来完全是没有问题的,居然会引发Heap corruption detected。代码大体如下:
     
    char* pCmd = new char[len+1];   // len has got value before
    memset( pCmd, 0, len+1);
    .........
    for(int i=0;i<len;i++) {
          ........      //获取一个str内容形如:"1A", "0F"
          sscanf(str, "%02X", &pCmd[i]);
    }
    .....
    delete [] pCmd;

    找到问题的所在,再分析代码才发现了这其中一个很隐蔽的问题,就是那句sscanf,由于第二个参数用的是"%02X",那么对它而言,最后一个参数就是一个指向int类型的指针了,而我给的实际是一个char的指针。
    如果上面的循环只进行到i<len-2,或者pCmd的size扩大到len+3,都可以避免heap corruption。
    后来我干脆用了一个零时的int型变量来完成这个工作。

    要分析这个问题,太理论化的我将不上来,应该是sscanf调用的过程中,由于pCmd分配到的空间不足,因此引发了新的分配,pCmd不再是像声明的那样一个len+1大小的char数组,因此直接调用delete [] pCmd就会引发heap corruption了。到底咋回事,也许还要高人来讲讲。
    http://www.cppblog.com/kerlw/archive/2007/04/12/21700.html

    前两天写程序的时候,一不小心引发了Heap Corruption,但是只是找出了引起问题的代码,并写进行了修正,没有时间去深入的探索一番,在博客上写了篇随笔,有些朋友留了些评论,让我颇感惭愧,这样一个问题为何不去深入探索一番呢,不能让它继续作为一个模糊的概念存在我的脑子里了,故而今天研究了一下,有些收获,拿出来分享。

            首先说明一下什么是Heap Corruption。当输入超出了预分配的空间大小,就会覆盖该空间之后的一段存储区域,这就叫Heap Corruption。这通常也被用作黑客攻击的一种手段,因为如果在该空间之后的那段存储区域如果是比较重要的数据,就可以利用Heap Corruption来把这些数据修改掉了,后果当然可想而知了。

            在VC里面,用release模式编译运行程序的时候,堆分配(Heap allocation)的时候调用的是malloc,如果你要分配10byte的空间,那么就会只分配10byte空间,而用debug模式的时候,堆分配调用的是_malloc_dbg,如果你只要分配10byte的空间,那么它会分配出除了你要的10byte之外,还要多出约36byte空间,用于存储一些薄记信息,debug堆分配出来之后就会按顺序连成一个链。

            那么我们再来看看薄记信息中有些什么。还是上面10byte分配空间的例子,那么分配出的10byte空间的前面会有一个32byte的附加信息,存储的是一个_CrtMemBlockHeader结构,可以在DBGINT.H中找到该结构的定义:

    typedef struct _CrtMemBlockHeader
    {
    // Pointer to the block allocated just before this one:
       struct _CrtMemBlockHeader *pBlockHeaderNext;
    // Pointer to the block allocated just after this one:
       struct _CrtMemBlockHeader *pBlockHeaderPrev;
       char *szFileName;    // File name
       int nLine;                  // Line number
       size_t nDataSize;      // Size of user block
       int nBlockUse;         // Type of block
       long lRequest;          // Allocation number
    // Buffer just before (lower than) the user's memory:
       unsigned char gap[nNoMansLandSize];
    } _CrtMemBlockHeader;

    /* In an actual memory block in the debug heap,
     * this structure is followed by:
     *   unsigned char data[nDataSize];
     *   unsigned char anotherGap[nNoMansLandSize];
     */

    结构中的_CrtMemBlockHeader结构两个指针就不用解释是干嘛的了,szFileName是存储的发起分配操作的那行代码所在的文件的路径和名称,而nLine则是行号。nDataSize是请求分配的大小,我们的例子里当然就是10了,nBlockUse是类型,而lRequest 是请求号。最后一项gap,又称NoMansLand,是4byte(nNoMansLandSize=4)大小的一段区域,注意看最后几行注释就明白了,在这个结构后面跟的是用户真正需要的10byte数据区域,而其后还跟了一个4byte的Gap,那么也就是说用户申请分配的区域是被一个头结构,和一个4byte的gap包起来的。在释放这10byte空间的时候,会检查这些信息。Gap被分配之后会被以0xFD填充。检查中如果gap中的值变化了,就会以Assert fail的方式报错。不过vc6中提示的比较难懂,DAMAGE :after Normal block(#dd) at 0xhhhhhhhh,而vs2005里面会提示Heap Corruption Detected!而如果你是release版本,那么这个错误就会潜伏直到它的破坏力发生作用。也许其后的区域存储着一个除数,而你的heap corruption把它改写成了0,那么会怎么样呢? :P
            至于其他的C/C++编译器中是否会有这样的机制,我就不是很清楚了,或许知道的朋友可以给我做些补充。

    下面是我的见解:

    我的出错程序:

    unsigned int tLength=strlen(inSrcString);

    char* tString=new char[tLength];     //注意这里!!!分配的数组大小应为tLength+1,因为最后还有一个''

    ...

    strcpy(tString,inSrcString);            //也要小心!如果inSrcString的长度大于tString的长度,会越界,显然Bug!本例先取inSrcString长度

    /*附上strcpy大概实现,想然你会明白我的意思。

    char* strcpy(char* pDest,const char* pSrc)

    {

    assert(pDest!=NULL&&pSrc!=NULL);

    char* addr=pDest;

    while((*pDest++=*pSrc++)!='');

    retrun addr;

    */

    ...

    delete[] tString;                  //字符数组,所以用delete[],就是这里报错!!!

    我想C++的字符串操作,我是说像我这么原始的,而不是string类,一定要千万小心!!!祝你好运!

    好了,我想我已经说明白了。如果你还不明白,再仔细琢磨琢磨吧。

    为防自己忘记,特记之。

  • 相关阅读:
    【SCOI 2011】 糖果
    【POJ 3159】 Candies
    【POJ 1716】 Integer Intervals
    【POJ 2983】 Is the information reliable?
    【POJ 1364】 King
    【POJ 1201】 Intervals
    【POJ 1804】 Brainman
    6月10日省中提高组题解
    【POJ 3352】 Road Construction
    【POJ 1144】 Network
  • 原文地址:https://www.cnblogs.com/wubugui/p/4107310.html
Copyright © 2011-2022 走看看