一切始於一段極簡單的代碼:
void main() {
char *p = new char;
cin >> p;
cout << p[2];
delete p;
}
輸入 abcd,螢幕正確輸出 c,但隨即彈出 Debug Error:DAMAGE: after Normal block(#64) at 0x003429f8。更詭異的是,若改為 cout << p; 且僅輸入單一字元 a,依然報錯。Release 模式卻一切正常,移除 delete p 錯誤也消失。問題核心在於 Debug 模式下的記憶體完整性檢查機制。
在 delete p 設中斷點,按 F11 進入原始碼世界:
DELOP.CPP:operator delete 僅呼叫 free(p)。DBGHEAP.C:Debug 堆積實作,最終在 _free_dbg 中遇到關鍵判斷:if (!CheckBytes(pbData(pHead) + pHead->nDataSize, _bNoMansLandFill, nNoMansLandSize))
_RPT3(_CRT_ERROR, "DAMAGE: after %hs block (#%d) at 0x%08X.\n", ...);
CheckBytes 負責驗證使用者資料區後方的 nNoMansLandSize(預設 4)個位元組是否全為 _bNoMansLandFill(0xFD)。若非,呼叫 _RPT3 產生錯誤報告。
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;
}
註釋說明:Purpose: verify byte range set to proper value。至此,原始碼追蹤到頭,仍未揭示哨兵何時、如何被植入。下一步必須直接監視記憶體,觀察 new char 執行前後的變化,才能揭開真相。