[英]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.