首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

VC 6.0 Debug 模式 new 運算子計數器溢位 Bug 終極解決方案

     編輯:關於C語言

問題現象與根因

維護中的 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();

嘗試過的替代方案(均失效或副作用大)

  1. UE 十六進位修改 msvcrtd.dll:將 0xCC (INT 3) 改為 0x90 (NOP)。風險高,且失去正規除錯中斷功能。
  2. 修改 Debug Report 模式:用 _CrtSetReportMode 導向 stdout。實測無法攔截此特定中斷。
  3. 引入 Memory Pool (Boost.Pool):治標不治本,MFC 內部大量 new 仍會觸發。
  4. 升級至 VS 2008 編譯:產生上千錯誤,修改一天勉強通過編譯,實際執行仍崩潰。

終極解法:重新編譯 CRT 靜態庫

關鍵發現:MFC 提供 CRT 原始碼與 Makefile (vc98/crt/src/),可自行編譯修正後的靜態庫。

  1. 修改 dbgheap.c,加入 _crtBreakAlloc != -1L 判斷
  2. 依照《重新編譯生成 C 執行階段庫》文件操作,執行 nmake 編譯
  3. 編譯過程中 msvcrtd.dll 會報錯停止,但 libcmt.lib (靜態多執行緒 Debug 庫) 可成功產出
  4. 專案設定改為「使用靜態連結 MFC/CRT」

重新建置專案後,計數器溢位不再觸發中斷,問題徹底解決。

避坑指南

  • 務必同步更新 libcmt.lib、libcmtd.lib 等所有靜態庫變體
  • 專案屬性 → C/C++ → Code Generation → Runtime Library 選 Multi-threaded Debug (/MTd)
  • 若專案包含 DLL,確保所有模組使用相同 CRT 版本,避免跨模組記憶體管理衝突

此法雖需靜態連結(執行檔體積略增),但徹底根治 VC 6.0 經典 Bug,且不犧牲除錯功能,為維護舊專案的最佳選擇。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved