生死疆界(上)--- 在new与delete之间

2016-01-29 12:20 23 1 收藏

生死疆界(上)--- 在new与delete之间,生死疆界(上)--- 在new与delete之间

【 tulaoshi.com - C语言心得技巧 】

生死疆界(上)--- 在new与delete之间
作者:土豆

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com) 问题源自一段简单的代码:
void main(){ char *p = new char; cin>>p; cout<<p[2]; delete p;} 
在以上代码中,如果你输入:abcd,那么如你所望,你会看到"正确"的输出"c"。但是会有错误提示出现:
Debug Error!
Program: test.exe
DAMAGE: after Normal block(#64) at 0x003429f8


更离奇的是,如果将代码改为如下的代码:
void(){char *p = new char;cin>>p;cout<<p;delete p;}
如果只输入一个字符a,那么依然报错。是不是奇怪,分配了一个字符,输入了一个字符,那么错在哪里? 注意,最开始那行Debug Error!说明这是在Debug编译模式下才有的提示,如果你换到release频道,那么此提示不再出现,你成功得到了"c",仿佛程序一切正常。

一个奇怪的现象是,如果去掉delete p这条语句,这个运行时错误消失了,甚至你在debug模式下也看不到这个提示。 问题何在?

以前我遇到过这种情况,分析后归结为一个结论:在debug模式下系统有一定的机制侦测到内存的非法访问。然后就放过这个问题。这个结论说了等于没说,关键在于,这种机制的具体运做过程。这次我下了狠心,不入虎穴,焉得虎子。我决定追进源代码里边去。 把编译环境设置成debug模式,很显然,问题出在delete p上,在这条语句设置断点,按F5,程序运行到这条语句前自动暂停,然后按F11。

Welcome to the Source Code World!

首先来到DELOP.CPP文件中,这个文件短小精悍,只有一个函数
void __cdecl operator delete(void *p) _THROW0(){ // free an allocated object free(p);}
没有任何有用的信息,那就继续追进free(p)里。 不一会,我们追到了DBGHEAP.C中,你从文件名可以看出,这是在debug模式下才能进入的文件。

最后在_CRTIMP void __cdecl _free_dbg(void * pUserData, int nBlockUse )中的这条语句
if (!CheckBytes(pbData(pHead) + pHead->nDataSize, _bNoMansLandFill, nNoMansLandSize))                _RPT3(_CRT_ERROR, "DAMAGE: after %hs block (#%d) at 0x%08X.n",                    szBlockUseName[_BLOCK_TYPE(pHead->nBlockUse)],                    pHead->lRequest,                    (BYTE *) pbData(pHead)); 
前受阻。 是不是觉得这这模块巨可怕,呵呵,静下心来,很简单,因为有if存在,那么CheckBytes()一定是执行某种检验,如果检验失败,调用_RPT3()函数 在MSDN中,对_RPT函数族有这样的解释:

Track an application''s progress by generating a debug report (debug version only).


_RPT3的作用就是产生一个错误报告。
好了,知道了这一点就足够了,它对我们来说没什么意义了。那么只剩下CheckBytes了,深呼吸几口,好了,让我们进去吧。
static int __cdecl CheckBytes(unsigned char * pb, unsigned char bCheck, size_t nSize){        int bOkay = TRUE;        while (nSize--)        {            if (*pb++ != bCheck)            {               _RPT3(_CRT_WARN, "memory check error at 0x%08X = 0x%02X, should be 0x%02X.n",                    (BYTE *)(pb-1),*(pb-1), bCheck);                bOkay = FALSE;            }        }        return bOkay;}
你看到了,这个函数只调用了_RPT3,再也没有其他的调用,看来,我们到头了。 下面是微软的程序员为这个函数写的注释的一部分:
*Purpose:*       verify byte range set to proper value*Return:*       TRUE - if all bytes in range equal bcheck*       FALSE otherwise
再明显不过了,这个函数检验一定范围的位是否设定为了正确的值(就是传进来的那么bCheck),如果正确,返回bOkay=TRUE,否则,返回bOkay=FALSE. 都挖完了,再也没有任何有用的信息,我们仍旧不知道微软是如何进行校验的,眼前依然一片黑暗。如果还有黎明的曙光,那么只能从传入的参数身上发出,呵呵,它们三肩负着我们的厚望啊。看看第一个参数unsigned char* pb。 if (*pb++ != bCheck)这条语句告诉我们要将pb所指内存地址的指与bCheck比较,那么我们还有最后一线希望:直接监视内存

欲知后事如何,且听下回分解 :)

来源:http://www.tulaoshi.com/n/20160129/1485684.html

延伸阅读
山 东 煤 炭 教 育 学 院 胡 振 山 郭 施 毅 ---- 过 程 式 编 程( 代 表 语 言C) 首 先 必 须 定 义 所 要 实 现 的 功 能, 然 后 设 计 为 实 现 这 些 功 能 所 必 须 的 步 骤。 此 步 骤 也 就 是 过 程。 编 写 代 码 实 际 上 等 同 于 分 解 这 些 步 骤, 使 每 一 步 直 接 对 应 一 行 代 码。 为 实 现 有 限 度 ...
Excel的引用分为绝对引用与相对引用,对一个单元格的引用实际上有四种组合,这里与大家分享下如何在这四种组合之间快速切换。 手动修改引用的类型效率是比较低的,下面与大家分享下快速更改引用类型的方法,从编辑栏中选中需要更改引用类型的内容,按下“F4”键,变为行列都是绝对引用,再连续按“F4”键就可以在列相对引...
徘徊在职场与厨房之间 男人卫国战场上,女人杀敌厨房中,男女各有发挥所长的空间。直到有了“职场”这个据说光怪陆离又五光十色的新天地,才把女人的心从厨房中引了出来。女人起初只是在门口探探,伸出一双脚测试外面的气候,一发现气温不对,立刻缩回脚来,全身而退,安安稳稳的回到厨房去做女王。 自从女性把头探...
标签: 孕前
情商胎教更能“制造”天才宝宝! 怀胎十月,孕妈咪同时担负着两个生命的新陈代谢和情绪起伏,实在不是件很轻松的事。而保持愉悦的心情则是对宝宝最好的胎教。所以说,胎教时情商重要于智商。 日本有一位母亲,培养出了4个天才儿女,她写了一本叫《胎儿都是天才》的书。书中,她并不主张努力去培养什么天才儿童,而是强调家长的爱心对胎儿...
标签: 孕前
想怀孕?不能这样喝…… 据报道,未育女性每天过多喝咖啡,有可能使日后受孕的机会降低。 医学专家指出,咖啡中含有丰富的咖啡因,女性过多摄入可致雌激素分泌减少,而体内雌激素水平下降,就有可能对卵巢的排卵功能构成不利影响,使得tulaoShi.com受孕机会降低。 美国的人群调查结果显示,平均每天喝...

经验教程

613

收藏

47
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部