0

我有一个使用 SQLite 文件作为文件格式的 Windows 窗体应用程序。这些文件由通过 C++/CLI 包装器调用的本机代码创建,其中包括对托管代码的回调以进行进度/取消更新。这对于 32 位非常有效。我试图通过切换到 64 位来消除我的内存上限,但遇到了一个主要障碍。

当在本机代码中分配或释放内存时,我会遇到伪确定性崩溃,这让我想到了内存损坏。但它只发生在发布构建期间,并且仅在没有附加调试器的情况下发生。这是我的噩梦的细分:

配置位 优化 互操作 Dbg-symbols 运行时 带调试器 不带调试器
Release 32 on no no / MD no crash no crash
Release 64 on yes no /MD no crash no crash
Release 32 on yes no /MD no crash no crash
Release 64 on yes no /MD no crash crash
Release 64 on yes yes /MD no crash crash
释放 64 关 是 否 /MD 不崩溃 不崩溃
释放 64 关 是 是 /MD 不崩溃 不崩溃
Debug 32 off no yes /MDd no crash no crash
调试 32 关闭 是 是 /MDd 没有崩溃 没有崩溃
调试 64 关闭 是 是 /MDd 没有崩溃 没有崩溃
调试 64 on yes yes /MD no crash no crash
调试 64 on yes no /MD no crash no crash
调试 64 关 是 是 /MD 不崩溃 不崩溃
调试 64 关闭 是 是 /MDd 没有崩溃 没有崩溃
Debug 64 on yes yes /MDd no crash no crash
调试 64 on yes no /MD no crash no crash

“互操作”意味着我使用 GUI 应用程序中的 C++/CLI 包装器来运行本机解析器代码。我有一个用本机 C++ 编写的命令行驱动程序,并且在任何配置中都不会崩溃。

基本上调试配置永远不会崩溃,即使本机代码完全像发布代码一样编译!我比较了响应文件,它们是相同的,除了我为调试配置添加了 _NO_DEBUG_HEAP=1 。我怀疑在使用 /MD 和定义 NDEBUG 时会产生任何影响。那么我该如何调试这个噩梦呢?感觉这不是我的代码的问题。请不要要求一个小的复制品,我不知道如何制作它。但是代码都是开源的,所以如果有人想尝试重现这个代码,我会发布一个指向源代码的链接。

4

1 回答 1

0

Heisenbugs 通常是由内存踩踏(在托管代码中不会发生)或将内存中的垃圾视为有效数据引起的。

我已经搜寻了多个通常可重现的 heisenbug,这些问题归结为使用未初始化的变量,该变量将从另一个例程中获取堆栈中的任何内容。您的本机代码可能包含这样一个错误,当它获得一个值时会起作用,而当它获得另一个值时会崩溃。Debug vs release 并不能保证幕后的东西是一样的(毕竟,如果它是为什么会有这两种配置呢?)而且你可能在内存中有不同的垃圾。

优化器也可能有这样的效果。

我会尝试的一件事是:在本机代码中的第一个例程的局部变量中添加一个实质性结构。对它做一些事情以防止链接器剥离它。

这将移动事物,如果它是内存中的垃圾问题,这应该会改变行为。

于 2012-06-13T22:48:19.527 回答