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

Posted

技术标签:

【中文标题】C# / C++ 应用程序在从 Windows 运行时崩溃,而不是从 Visual Studio 运行【英文标题】:C# / C++ application crashes when run from Windows, but not from Visual Studio 【发布时间】:2015-01-07 08:53:40 【问题描述】:

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

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

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

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

【问题讨论】:

显示你的代码,可能还有错误截图 为什么在 C++ 中使用malloc?请记住,它只分配内存,不调用对象的构造函数。您可以更改为new,并编写一些断言来测试您的不变量。 您的应用程序是多线程的吗?如果是这样,从调试切换到发布有时会揭示竞争条件。或者,尝试编写 C# 代码的 C++ 等效版本,看看代码的互操作部分是否存在问题。 @David:这是崩溃产生的结果:screencast.com/t/ecDZ4K5pAXbq。 dll 代码来自 Seismic Unix (tinyurl.com/ntoyxcd),我正在(部分)移植到 Windows 以在我的项目中使用。显示代码并不容易,因为原始代码是一团乱七八糟的意大利面条(即对“malloc”的实际调用隐藏在许多函数深处,与使用它的位置不同等)。我更感兴趣的是让它在 Visual Studio 中崩溃以自己调试崩溃,而不是帮助找出崩溃。 在进程启动后使用工具+附加到进程来附加调试器。您还可以在 C# 代码中使用 Debugger.Launch()。 【参考方案1】:

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

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

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

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

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

【讨论】:

优秀而彻底的答案......谢谢!在我原来的问题上结合使用这个和 cmets,我能够附加和重现我遇到的这个(以及其他几个)运行时问题。接受。 对于那些感兴趣的人,这里有一些关于调试堆的更多信息:preshing.com/20110717/…

以上是关于C# / C++ 应用程序在从 Windows 运行时崩溃,而不是从 Visual Studio 运行的主要内容,如果未能解决你的问题,请参考以下文章

C# 程序无法从 C++ COM 程序中获取字节数组

Windows 下 C++ 和 C# 中的套接字无法正常工作

如何从 C++ 后台任务(Windows 通用应用程序)调用 C# 函数?

如何使用 Windows 运行时使用 C# 实现 C++ API?

在 C# WPF 或 Windows 窗体应用程序中使用 DirectX c++ DLL

C# Windows 窗体无法在 Windows10 上加载非托管 C++ DLL