>p;cout<>p" />

欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

生死疆界--- 在new與delete之間

系統(tǒng) 2187 0
問題源自一段簡單的代碼:
    void main()

{

 char *p = new char;

 cin>>p;

 cout<<p[2];

 delete p;

} 


  
在以上代碼中,如果你輸入:abcd,那么如你所望,你會看到"正確"的輸出"c"。但是會有錯誤提示出現(xiàn):
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頻道,那么此提示不再出現(xiàn),你成功得到了"c",仿佛程序一切正常。

一個奇怪的現(xiàn)象是,如果去掉delete p這條語句,這個運行時錯誤消失了,甚至你在debug模式下也看不到這個提示。 問題何在?

以前我遇到過這種情況,分析后歸結為一個結論:在debug模式下系統(tǒng)有一定的機制偵測到內(nèi)存的非法訪問。然后就放過這個問題。這個結論說了等于沒說,關鍵在于,這種機制的具體運做過程。這次我下了狠心,不入虎穴,焉得虎子。我決定追進源代碼里邊去。 把編譯環(huán)境設置成debug模式,很顯然,問題出在delete p上,在這條語句設置斷點,按F5,程序運行到這條語句前自動暫停,然后按F11。

Welcome to the Source Code World!

首先來到 DELOP.CPP 文件中,這個文件短小精悍,只有一個函數(shù)
    void __cdecl operator delete(void *p) _THROW0()

{ // free an allocated object

 free(p);

}


  
沒有任何有用的信息,那就繼續(xù)追進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()一定是執(zhí)行某種檢驗,如果檢驗失敗,調(diào)用_RPT3()函數(shù) 在MSDN中,對_RPT函數(shù)族有這樣的解釋:

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


_RPT3的作用就是產(chǎn)生一個錯誤報告。
好了,知道了這一點就足夠了,它對我們來說沒什么意義了。那么只剩下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;

}


  
你看到了,這個函數(shù)只調(diào)用了_RPT3,再也沒有其他的調(diào)用,看來,我們到頭了。 下面是微軟的程序員為這個函數(shù)寫的注釋的一部分:
    *Purpose:

*       verify byte range set to proper value

*Return:

*       TRUE - if all bytes in range equal bcheck

*       FALSE otherwise


  
再明顯不過了,這個函數(shù)檢驗一定范圍的位是否設定為了正確的值(就是傳進來的那么bCheck),如果正確,返回bOkay=TRUE,否則,返回bOkay=FALSE. 都挖完了,再也沒有任何有用的信息,我們?nèi)耘f不知道微軟是如何進行校驗的,眼前依然一片黑暗。如果還有黎明的曙光,那么只能從傳入的參數(shù)身上發(fā)出,呵呵,它們?nèi)缲撝覀兊暮裢 ?纯吹谝粋€參數(shù)unsigned char* pb。 if (*pb++ != bCheck)這條語句告訴我們要將pb所指內(nèi)存地址的指與bCheck比較,那么我們還有最后一線希望: 直接監(jiān)視內(nèi)存
還記得我們在delete p;前設的斷點嗎?好,讓我們重新開始調(diào)試,按F5,從控制臺輸入"abcd",然后到這條語句前停止了,查看變量p的值,是0x00342c40,那好,打開vc監(jiān)視內(nèi)存的窗口memory,我們查看這個地址的值:


此后的內(nèi)存情況不再用圖片顯示。只用紅色標志的內(nèi)存表示發(fā)生了變化的內(nèi)存

看到了嗎?你的寶貝"abcd"乖乖地躺在內(nèi)存中,其后跟了一個0x00,那表示''/0'',字符串結束標志。一切都很正常,到底哪里出錯了?難道是delete p用錯了,而應該用delete[] p?try it,你會發(fā)現(xiàn)依然有相同的錯誤。

從這段內(nèi)存中仍然看不出問題,仿佛一切風平浪靜,其實是我們來晚了,在delete p前,內(nèi)存早已經(jīng)發(fā)生了翻天覆地的變化。 再一次重新進入程序,這次我們從一開始就監(jiān)視內(nèi)存。

00342C40 EE FE EE FE EE FE EE 鉿鉿鉿.
00342C47 FE EE FE EE FE EE FE .


這是char *p = new char,執(zhí)行前的內(nèi)存。下面是執(zhí)行后的:

00342C40 CD FD FD FD FD F0 AD 妄.
00342C47 BA 0D F0 AD BA 0D F0 ..瓠...


看不出什么問題,再往下執(zhí)行吧:(cin>>p, 這次我們輸入ab)

00342C40 61 62 00 FD FD F0 AD ab.
00342C47 BA 0D F0 AD BA 0D F0 ..瓠...


ab正確地放進了內(nèi)存中,而且你可以看到cin還體貼地在ab后為你放了一個''/0''

還是沒有什么問題?再往下走就是cout<<p了,它不會改動內(nèi)存,再往下就到了delete p,到那時一切都晚了。 沒錯,就是這一步,靜靜的內(nèi)存中早已經(jīng)翻江倒海。

還記得static int __cdecl CheckBytes(unsigned char * pb, unsigned char bCheck, size_t nSize)中的bCheck, nSize嗎? 如果當初你也監(jiān)視變量的話,會發(fā)現(xiàn)bCheck = 253, nSize = 4。這就是這個內(nèi)存?zhèn)蓽y機制的命門。小時候喜歡看武打片,有一部叫做〈鷹爪鐵布衫〉的,當時令我如癡如醉啊,看過的人一定還記得最后殺那老頭的時候是先在他天靈上一拍,接著再在褲襠上捏一把,呵呵,bCheck就是天靈,nSize就是褲襠。

把253轉(zhuǎn)換為16進制,是什么,沒錯,是FD。呵呵,別忙往下看,想一想,你找到真相了嗎? 再看一眼char *p = new char執(zhí)行后的內(nèi)存,你發(fā)現(xiàn)了什么?p指向0x00342c40那個字節(jié)的值為CD,這是屬于你的內(nèi)存,看看后邊跟的是什么,不多不少, 恰恰是4個FD,恰恰是nSize個bCheck!

這個偵測內(nèi)存非法訪問的機制現(xiàn)在已經(jīng)被我們開膛破肚了。微軟在你申請的空間后加上四個FD,如果你訪問了你非法訪問內(nèi)存,那么這些內(nèi)存的內(nèi)容將被改變(有一個問題我沒有解決,我不知道FD代表什么,望知道的兄弟教我),在delete時,將檢查由new產(chǎn)生的''/0''結束符后是否有連續(xù)四個字節(jié)都是FD,如果有證明沒有發(fā)生非法內(nèi)存訪問,如果沒有,那就該讓_RPT3老兄出馬了。
對于
    char *p = new char;

cin>>p;

cout<<p;

delete p;


  
這段代碼,如果只輸入一個字符a,cin>>p執(zhí)行后的內(nèi)存為

00342C40 61 00 FD FD FD F0 AD a. .
00342C47 BA 0D F0 AD BA 0D F0 ..瓠...


雖然你只用了你申請的內(nèi)存,但是cin為了討好你給你加那個''/0'',覆蓋了一個FD,這樣,delete時照樣報錯,如果你這樣做
    char *p = new char[2];
  
那么cin>>p后內(nèi)存為

00342C40 61 00 FD FD FD FD AD a. .
00342C47 BA 0D F0 AD BA 0D F0 ..瓠...


那么程序?qū)⒉粫箦e。 四個FD就是內(nèi)存的生死疆界,超過這個疆界,呵呵,聽見遠方傳來的崩潰的聲音了嗎? 到此,一切真相大白,山高月小,水落石出!

(尾聲:以上所有內(nèi)容皆來自筆者獨立分析,其中難免有錯,更甚者,也許我大錯特錯,壓根就不是這樣的機制。如果你發(fā)現(xiàn)其中有不正確的地方,請指出,謝謝,在下感激不盡)。

生死疆界--- 在new與delete之間


更多文章、技術交流、商務合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 亚洲一区二区三区在线免费观看 | 成人福利网 | 看免费大片 | 久久久无码精品亚洲日韩按摩 | 亚洲欧洲精品一区二区三区 | 国产精品网址 | 日本高清免费h色视频在线观看 | 久久久久毛片免费观看 | 亚洲男人天堂网 | 亚洲一区二区久久 | 午夜天堂精品久久久久 | 精精国产xxxx视频在线 | 成人免费观看网欧美片 | 亚洲我不卡 | 乱淫毛片 | 国产图片区 | 国产精品久久人妻无码网站一区无 | 狠狠色噜噜狠狠狠狠黑人 | 欧美另类69xxxxx免费 | 仇爱电视剧泰剧在线观看免费播放 | av网址在线播放 | 欧美欲乱妇135 | 亚洲美女亚洲精品久久久久 | 午夜视频日本 | 精品国产一区二区三区香蕉沈先生 | 五月婷婷丁香 | 亚洲国产最新 | 亚洲国产精品一区二区久久 | 日本欧美中文字幕人在线 | 亚洲欧洲在线视频 | 日韩精品av一区二区三区 | 看中国毛片 | 国产91小视频在线观看 | 亚洲午夜精品久久久久久成年 | 天天干天天天天 | 精品亚洲一区二区三区四区五区 | 精品热99| 男进女内免费视频无遮挡 | 国产一区亚洲 | 天天摸夜夜摸夜夜狠狠摸 | 国产色司机在线视频免费观看 |