这个问题在这里已经有答案了:

我有一个小型单线程 C++ 应用程序,使用 Visual Studio 2005 进行编译和链接,它使用 boost(crc、program_options 和 tokenizer)、少量 STL 以及各种其他系统头文件。

(它的主要目的是读取 .csv 并生成自定义二进制 .dat 和配对的 .h 声明结构,“解释”.dat 的格式。)

当在调试器之外运行时,该工具会崩溃(NULL 上的访问冲突),仅在发布版本中。例如。按 F5 不会导致工具崩溃,而 Ctrl-F5 则会导致工具崩溃。当我重新连接调试器时,我得到这个堆栈:

ntdll.dll!_RtlAllocateHeap@12()  + 0x26916 bytes    
csv2bin.exe!malloc(unsigned int size=0x00000014)  Line 163 + 0x63 bytes C
csv2bin.exe!operator new(unsigned int size=0x00000014)  Line 59 + 0x8 bytes C++
>csv2bin.exe!Record::addField(const char * string=0x0034aac8)  Line 62 + 0x7 bytes  C++
csv2bin.exe!main(int argc=0x00000007, char * * argv=0x00343998)  Line 253   C++
csv2bin.exe!__tmainCRTStartup()  Line 327 + 0x12 bytes  C

它崩溃的线路是一个看起来无害的分配:

pField = new NumberField(this, static_cast<NumberFieldInfo*>(pFieldInfo));

...我不相信它已经到达构造函数,它只是在跳转到构造函数之前分配内存。当它崩溃时,它还执行了该代码数十次,通常是在一致(但不可疑)的位置。

当使用 /MTd 或 /MDd(调试运行时)编译时,该问题消失,而当使用 /MT 或 /MD 时,该问题又出现。

NULL 是从堆栈加载的,我可以在内存视图中看到它。_RtlAllocateHeap@12 + 0x26916 字节似乎是 巨大的 偏移,就像进行了错误的跳跃一样。

我试过了 _HAS_ITERATOR_DEBUGGING 在调试版本中并且没有出现任何可疑的情况。

在 Record::addField 的开头和结尾处删除 HeapValidate 会显示直到崩溃时堆都正常。

这曾经是有效的——我不完全确定从现在到我们上次编译该工具(可能是几年前,也许在旧的 VS 下)之间发生了什么变化。我们尝试了旧版本的 boost(1.36 与 1.38)。

在返回手动调查代码或将其提供给 PC-Lint 并梳理其输出之前,有关于如何有效调试此代码的建议吗?

[如果您在评论中请求信息,我很乐意用更多信息更新问题。]

有帮助吗?

解决方案

附加调试器与不附加调试器运行之间的一个鲜为人知的区别是操作系统调试堆(另请参阅 当我附加调试器时,为什么我的代码运行缓慢?)。您可以使用环境变量 _NO_DEBUG_HEAP 关闭调试堆。您可以在计算机属性中或在 Visual Studio 的项目设置中指定此项。

一旦关闭调试堆,即使附加了调试器,您也应该看到相同的崩溃。

也就是说,请注意内存损坏可能很难调试,因为损坏的真正原因(例如某些缓冲区溢出)可能与您看到的症状(崩溃)相去甚远。

其他提示

应用验证器 一旦我在环境中有 _NO_DEBUG_HEAP=1 ,对于解决这个问题非常有用,请参阅此处接受的答案: 查找内存最后被释放的位置?

也许还值得一提 页堆, ,这是我在查看应用程序验证器时发现的。看起来它涵盖了一些相似的领域。

(仅供参考,这是一个单字符缓冲区溢出:

m_pEnumName = (char*)malloc(strlen(data) /* missing +1 here */);
strcpy(m_pEnumName, data);

...又是一个不使用的荒谬的好论据 strcpy 直接地。)

new 或 malloc 内部崩溃通常表明 malloc 实现的(内部)结构已损坏。大多数情况下,这是通过写入先前的分配(缓冲区溢出)来完成的。然后,在下次调用 new 或 malloc 时,应用程序崩溃,因为内部结构现在包含无效数据。

检查是否可以覆盖任何以前分配的空间。

如果您的应用程序是可移植的,您可以尝试在 Linux 上构建它并在 瓦尔格林德.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top