我有一个相当大的解决方案偶尔会崩溃。遗憾的是,这些崩溃似乎只发生在发布版本中。当我在崩溃时附加调试器时,我收到消息:
“任何通话都没有加载符号 堆栈框架。源代码不能 显示“
这使得很难找到崩溃的原因。我正在使用visual studio 2008的默认版本构建设置,其中“调试信息格式”设置为“程序数据库(/ Zi)”。
你有什么提示可以帮我找到这个bug吗?例如,我是否可以更改项目中的某些设置,以便崩溃可能仍然发生但在调试器中获取更有意义的信息?
更新:问题是一个非常罕见的逻辑错误,它本身不会导致崩溃,但显然会导致其他地方崩溃。解决逻辑错误解决了崩溃行为。
对于那些来到这里寻找解决类似问题的人来说:运气好的话,你是一个艰难的旅程。最终帮助我找到问题的是在代码中添加了大量的边界检查(我可以使用预处理器指令启用/禁用)并为linux编译并使用gdb / valgrind运行。
答案 0 :(得分:5)
首先确保您为发布版本构建符号(调试信息),并且调试器可以找到它们(这可能需要配置符号路径 - 符号服务器会更好)。
第二次在调试时使用Modules视图以确认您已加载符号。
获取符号的最简单方法是将.pdb
文件放在与程序集相同的位置。
查看John Robbins blog了解更多详细信息。
答案 1 :(得分:5)
如果代码在应用优化后崩溃(如在默认版本中),则很可能是您的代码存在某些缺陷,并且依赖于在发布和调试版本之间发生变化的未定义行为。
尝试在发布版本中关闭优化以查看问题是否消失(或在调试版本中将其打开以查看是否发生)。如果确实如此,你仍然应该找到并修复bug,但你至少会知道要寻找未定义的行为。
将编译器警告级别设置为最大值(/ W4),将警告设置为错误(/ Wx)并修复所有警告(而不是简单地将所有内容都放在视线中 - 考虑一下!)。应用优化后,由于执行了更广泛的代码分析,您可能会收到调试版本中未出现的警告 - 这是非常有用的静态分析。
如果您希望在优化版本中进行切换调试,可以使用,但由于优化器可能会重新排序代码并删除代码和变量,因此您不太可能按照正在进行的操作进行调整。
答案 2 :(得分:4)
调试版本可能不允许缺陷表达自身的几个原因:
由于您使用的是C ++,您可以考虑使用像valgrind这样的静态分析工具来指出可能未初始化的数据和指针处理错误。
可以通过添加带时间戳的日志输出来跟踪竞争条件。您首先必须通过观察崩溃之前发生的事情来缩小问题发生的“大解决方案”中的位置。请务必使用延迟日志记录机制 - 稍后或在另一个线程中执行字符串处理的机制,因此它本身不会对时间造成太大影响。
答案 3 :(得分:4)
听起来像堆栈框架被吹了。处理缓冲区溢出很简单,只需在小char []中复制一个大字符串即可。这消灭了返回地址。代码只是一直运行直到返回,然后在它从堆栈中弹出一个坏地址时爆炸。或者更糟糕的是,如果地址恰好有效。
调试器无法显示任何有意义的内容,因为它无法遍历堆栈以向您显示代码如何到达崩溃位置。实际的碰撞位置不会告诉你任何事情。
Tuff作为指甲调试。你必须让它具有可重复性,你需要步进或跟踪来找到最后一个已知良好的功能。在走出它之后产生崩溃的那个是带有bug的那个。你实际上可以看到造成损害的声明,调试器调用栈突然变成了紧张性精神病。如果您无法获得一致的repro,那么只需进行彻底的代码审查即可。你可以称之为“安全审查”来证明时间的合理性。祝你好运。
答案 4 :(得分:1)
您知道您仍然可以调试发布版本吗?只需按F5(而不是CTRL + F5)即可在调试中运行。
它是否可重复,即你在爆炸时做某些特定事情?
如果是这样,请在崩溃前在代码中设置一个断点,然后点击F5在debug中运行(确保你正在使用你的发布版本)。然后单步执行直到您的应用崩溃。我通常发现这比添加日志记录和调试打印语句更快。
如果没有,只是在调试模式下运行有时会捕获错误并停止在违规行上。
如果不这样,Richard和Amar的答案很好: - )
答案 5 :(得分:0)
未初始化的变量(可能是指针)也可能导致问题。也许您应该对代码运行静态分析程序 - CppCheck也不错。