[英]Common reasons for bugs in release version not present in debug mode
僅在發布編譯模式下出現但在調試模式下不出現的錯誤和異常程序行為的典型原因是什么?
很多時候,在 C++ 的調試模式下,所有變量都是空初始化的,而除非明確說明,否則在發布模式下不會發生同樣的情況。
檢查任何調試宏和未初始化的變量
您的程序是否使用線程,那么優化也會導致發布模式出現一些問題。
還要檢查所有異常,例如與發布模式沒有直接關系,但有時我們只是忽略一些關鍵異常,例如 VC++ 中的內存訪問沖突,但至少在其他操作系統(如 Linux、Solaris)中同樣可能存在問題。 理想情況下,您的程序不應捕獲諸如訪問 NULL 指針之類的關鍵異常。
一個常見的陷阱是在 ASSERT 中使用具有副作用的表達式。
過去,我被許多錯誤所困擾,這些錯誤在 Debug 版本中很好,但在 Release 版本中會崩潰。 有許多根本原因(當然包括本主題中已經總結的那些),並且我已經被以下所有原因所吸引:
#ifdef _DEBUG
中的成員變量或成員函數,以便類在調試版本中具有不同的大小。 有時#ifndef NDEBUG
用於發布版本#ifdef
恰好只出現在兩個版本之一中#pragma pack
類的東西尚未重置,那么這可能會導致嚴重的問題。 使用預編譯頭和強制包含也會出現類似問題我多年來積累的一些用於深入調試/發布錯誤的技巧:
其他差異可能是:
是的!,如果您有條件編譯,則可能存在計時錯誤(優化的發布代碼節,未優化的調試代碼)、內存重用與調試堆。
它可以,特別是如果您在 C 領域。
一個原因可能是 DEBUG 版本可能會添加代碼來檢查雜散指針並以某種方式保護您的代碼免於崩潰(或行為不正確)。 如果是這種情況,您應該仔細檢查從編譯器獲得的警告和其他消息。
另一個原因可能是優化(通常對發布版本打開,在調試時關閉)。 代碼和數據布局可能已經優化,而您的調試程序只是,例如,訪問未使用的內存,而發布版本現在正在嘗試訪問保留內存甚至指向代碼!
編輯:我看到其他人提到了它:當然,如果不在調試模式下編譯,您可能有整個代碼部分被有條件地排除在外。 如果是這樣,我希望這真的是調試代碼,而不是對程序本身的正確性至關重要的東西!
CRT 庫函數在調試與發布(/MD 與 /MDd)中的行為不同。
例如,調試版本通常會預填充您傳遞給指定長度的緩沖區以驗證您的聲明。 例子包括strcpy_s
, StringCchCopy
,等等。即使琴弦較早終止,您szDest最好是N久字節!
當然,例如,如果您使用類似的結構
#if DEBUG
//some code
#endif
在非 void 函數中,所有執行路徑都應以 return 語句結束。
在調試模式下,如果您忘記用 return 語句結束這樣的路徑,那么該函數通常默認返回 0。
但是,在發布模式下,您的函數可能會返回垃圾值,這可能會影響程序的運行方式。
您需要提供更多信息,但是是的,這是可能的。 這取決於您的調試版本的作用。 您可能會進行日志記錄或額外檢查,這些檢查不會被編譯到發布版本中。 這些僅用於調試的代碼路徑可能會產生意想不到的副作用,這些副作用會以奇怪的方式改變狀態或影響變量。 調試構建通常運行速度較慢,因此這可能會影響線程和隱藏競爭條件。 與發布編譯的直接優化相同,發布編譯可能(盡管現在不太可能)將某些內容作為優化短路。
沒有更多細節,我會假設“不正常”意味着它要么不編譯,要么在運行時拋出某種錯誤。 檢查您是否有依賴編譯版本的代碼,通過#if DEBUG
語句或通過標記有Conditional
屬性的方法。
在 .NET 中,即使您不使用#if DEBUG
類的條件編譯,編譯器在發布模式下的優化仍然比在調試模式下更加自由,這也可能導致僅發布錯誤。
有些編譯器優化可能會破壞有效代碼,因為它們過於激進。
嘗試在啟用較少優化的情況下編譯您的代碼。
這是可能的,如果你有條件編譯,使得調試代碼和發布代碼不同,並且代碼中有一個只在發布模式下使用的錯誤。
除此之外,這是不可能的。 調試代碼和發布代碼的編譯方式有所不同,代碼在調試器下運行與否的執行方式也有所不同,但如果這些差異中的任何一個導致性能差異以外的任何其他原因,那么問題就一直存在。
在調試版本中,錯誤可能不會發生(因為時間或內存分配不同),但這並不意味着錯誤不存在。 也可能還有其他與調試模式無關的因素改變了代碼的時序,導致錯誤發生與否,但歸根結底,如果代碼正確,錯誤就不會發生在任何情況下。
所以,不,調試版本不能僅僅因為您可以運行它而不會出錯。 如果在發布模式下運行時發生錯誤,那不是因為發布模式,而是因為錯誤從一開始就存在。
這是可能的。 如果它發生並且不涉及條件編譯,那么您可以非常確定您的程序是錯誤的,並且僅由於偶然的內存初始化甚至內存布局而在調試模式下工作!
我剛剛在調用未恢復寄存器先前值的匯編函數時遇到過這種情況。
在“發布”配置中,VS 使用 /O2 進行編譯,這優化了代碼的速度。 因此,一些局部變量僅映射到與上述函數共享的 CPU 寄存器(用於優化),從而導致嚴重的內存損壞。
無論如何,看看您是否沒有在代碼中的任何地方間接弄亂 CPU 寄存器。
我記得不久前我們在 c/c++ 中構建 dll 和 pdb。
我記得這個:
然后繼續經歷那個循環。
我們有時會臨時交換 dll 的調試版本的發行版,以免在處理這些錯誤時推遲生產。
另一個原因可能是數據庫調用。 您是否在同一線程中多次保存和更新同一記錄,有時是為了更新。 更新失敗或未按預期工作可能是因為之前的創建命令仍在處理中,而對於更新,db 調用未能找到任何記錄。 這不會在調試中發生,因為調試器確保在登陸前完成所有掛起的任務。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.