我有一个使用SQLite文件作为文件格式的Windows窗体应用程序。这些文件由本机代码创建,通过C++/CLI Package 器调用,其中包括对托管代码的回调,以进行/取消更新。这对于32位来说非常有用。我正试图通过切换到64位来消除我的内存上限,但遇到了一个重大障碍。
当在本机代码中分配或释放内存时,我会遇到伪确定性崩溃,这让我想到内存损坏。但它只发生在发布构建期间,并且只在没有附加调试器的情况下。以下是我噩梦的一部分:
Config Bits Optimizations Interop Dbg-symbols Runtime With-debugger Without-debugger
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
Release 64 off yes no /MD no crash no crash
Release 64 off yes yes /MD no crash no crash
Debug 32 off no yes /MDd no crash no crash
Debug 32 off yes yes /MDd no crash no crash
Debug 64 off yes yes /MDd no crash no crash
Debug 64 on yes yes /MD no crash no crash
Debug 64 on yes no /MD no crash no crash
Debug 64 off yes yes /MD no crash no crash
Debug 64 off yes yes /MDd no crash no crash
Debug 64 on yes yes /MDd no crash no crash
Debug 64 on yes no /MD no crash no crash
“Interop”意味着我使用GUI应用程序中的C++/CLI Package 器来运行本机解析器代码。我有一个用原生C++编写的命令行驱动程序,它在任何配置下都不会崩溃。
基本上调试配置永远不会崩溃,即使本机代码完全像发布代码一样编译!我已经比较了响应文件,它们是相同的,除了我为调试配置添加了_NO_DEBUG_HEAP=1。我怀疑这对使用/MD和定义NDEBUG有什么影响。那么我该如何调试这个噩梦呢?我不觉得这是我代码的问题。请不要要求一个小的复制,我不知道如何使它。但是代码都是开源的,所以如果有人想复制这个,我会发布一个源代码的链接。
更新:我发现通过关闭C#项目中的“优化代码”可以避免崩溃(这就是为什么带有本地优化的调试配置可以正常工作)。这怎么会导致本机代码崩溃呢?!
1条答案
按热度按时间csga3l581#
Heisenbugs通常是由内存踩踏(这在托管代码中不会发生)或将内存中的垃圾视为有效数据引起的。
我已经找到了多个可复制的海森堡错误,它们归结为使用未初始化的变量,该变量将从另一个例程中获取堆栈上的任何内容。您的本机代码可能包含这样一个bug,它在获得一个值时工作,而在获得另一个值时崩溃。调试与发布并不能保证幕后的东西是相同的(毕竟,如果是这样,为什么会有两个配置?)),你可以在内存中有不同的垃圾。
优化器也可以具有这样的效果。
有一件事我会尝试:在本机代码中的第一个例程的局部变量中插入一个实质性的结构。对它做些什么,以防止链接器剥离它。
这将移动周围的东西,如果它是一个垃圾在内存中的问题,这应该改变的行为。