維護中的 VC 6.0 專案每月固定崩潰一次。分析 DMP 檔案發現,崩潰點落在 CRT 原始碼 dbgheap.c 的 _heap_alloc_dbg() 函式。該函式使用 long 型別變數 lRequest 作為配置計數器,當計數達到 LONG_MAX (2,147,483,647) 時,觸發 _CrtDbgBreak() 導致程式中斷:
/* VC 6.0 原始碼片段 */
if (lRequest == _crtBreakAlloc)
_CrtDbgBreak();
VS 2003 已修正此邏輯,加入 _crtBreakAlloc != -1L 判斷:
/* VS 2003 修正版 */
if (_crtBreakAlloc != -1L && lRequest == _crtBreakAlloc)
_CrtDbgBreak();
0xCC (INT 3) 改為 0x90 (NOP)。風險高,且失去正規除錯中斷功能。_CrtSetReportMode 導向 stdout。實測無法攔截此特定中斷。new 仍會觸發。關鍵發現:MFC 提供 CRT 原始碼與 Makefile (vc98/crt/src/),可自行編譯修正後的靜態庫。
dbgheap.c,加入 _crtBreakAlloc != -1L 判斷nmake 編譯msvcrtd.dll 會報錯停止,但 libcmt.lib (靜態多執行緒 Debug 庫) 可成功產出重新建置專案後,計數器溢位不再觸發中斷,問題徹底解決。
libcmt.lib、libcmtd.lib 等所有靜態庫變體此法雖需靜態連結(執行檔體積略增),但徹底根治 VC 6.0 經典 Bug,且不犧牲除錯功能,為維護舊專案的最佳選擇。