C# / C++ 应用程序在从 Windows 运行时崩溃,但从 Visual Studio 运行时不会崩溃

C# / C++ application crashes when run from Windows, but not from Visual Studio

我正在开发调用非托管 (C++) dll 的 C# 应用程序。我发现某个用户操作在从 Windows Explorer 运行时始终会导致应用程序崩溃。但是,从 Visual Studio 调试器启动时,不会发生崩溃。因此,我无法在崩溃时进入代码并准确调试发生了什么。

什么可能导致二进制文件在从资源管理器运行时崩溃,而不是从 Visual Studio 运行?请注意,我使用的是发布版本;调试构建在 Explorer 的 Visual Studio 中均未崩溃。

(如果相关,我可以说崩溃与在 C++ DLL 中操作 malloc 分配的数组有关。我通过煞费苦心地注释掉代码块、重建、从 [=16 运行来追踪它=], 并检查是否发生崩溃。但是,我已经到了无法在调试器中正确中断的情况下很难继续进行的地步。

我只对能够在 Visual Studio 内重现崩溃感兴趣。

当一个程序在调试中工作但在发布中崩溃时,问题通常是缓冲区溢出,所以你应该寻找错误的缓冲区长度变量之类的东西。

关于为什么调试的时候不死机,这里有一篇小文章side effects of debugger。如您所见,当调试器 启动 程序时,堆可能会有不同的行为。缓冲区溢出经常发生在堆上,你说它可能发生在 malloc-ed 缓冲区上,所以这就是原因。

现在,要让你的程序在调试时崩溃,唯一的方法可能是在启动后附加。如果在 DLL 项目中设置断点不起作用,请尝试使用 DLL 项目启动调试,并将您的可执行文件指定为 DLL 宿主。如果你不能像那样命中断点,那么,你总是可以在汇编代码中设置断点,这应该总是有效的,但并不实用。您可以在 MSVC 上使用 __debugbreak() 添加已编译的程序集断点。

请注意,即使在附加时仍可能会出现差异,调试器总是会稍微改变目标行为。虽然只有未定义的行为应该改变。

编辑: 我错过了,但文章说您可以通过设置环境变量 _NO_DEBUG_HEAP = 1 来禁用调试堆。这可能是调试问题的最简单解决方案(如果有效)。