【发布时间】:2015-02-19 12:56:22
【问题描述】:
我们使用自动崩溃报告工具(即http://crashrpt.sourceforge.net)来生成崩溃报告。
因此,例如,如果一段非托管代码因访问 NULL 指针而失败,则应用程序崩溃,崩溃报告工具将激活,我们会获得可用的堆栈跟踪来诊断和分组问题。
问题在于 .NET 在某些情况下似乎会干扰崩溃处理。一个示例如下:
this.Dispatcher.BeginInvoke((ThreadStart)delegate
{
// Send message to unmanaged control for performing a specific task.
User32.SendMessage(...);
}, DispatcherPriority.Input);
如果非托管组件随后因访问冲突而失败,内部 .NET 方法会捕获实际上应该是崩溃的 AccessViolationException 并首先将其重新包装在 TargetInvocationException 中,然后崩溃(如果不使用方法,它将不会这样做调用)。
这非常不方便,因为本机堆栈信息完全丢失了。剩下的是以下堆栈,与非托管部分发生故障的确切位置无关:
kernelbase!RaiseException+0x6c
clr!RaiseTheExceptionInternalOnly+0x276
clr!RaiseTheException+0x86
clr!RaiseTheExceptionInternalOnly+0x30a
clr!RealCOMPlusThrow+0x2f
clr!ThrowInvokeMethodException+0xac
clr!RuntimeMethodHandle::InvokeMethod+0xa64
mscorlib_ni+0x2d37b1
mscorlib_ni+0x2cf92a
windowsbase_ni+0xd77b1
windowsbase_ni+0xd768a
windowsbase_ni+0xc2d5c
windowsbase_ni+0xc2c98
mscorlib_ni+0x302346
mscorlib_ni+0x302301
windowsbase_ni+0xc2b9b
windowsbase_ni+0xd640b
windowsbase_ni+0xd65ca
windowsbase_ni+0xd798b
windowsbase_ni+0xd78db
windowsbase_ni+0xd7756
windowsbase_ni+0xd768a
windowsbase_ni+0xd5cae
windowsbase_ni+0xd71e1
user32!InternalCallWinProc+0x23
user32!UserCallWinProcCheckWow+0x100
user32!DispatchMessageWorker+0x3ef
user32!DispatchMessageW+0x10
windowsbase_ni+0xddca8
windowsbase_ni+0xd5636
windowsbase_ni+0xd5325
windowsbase_ni+0xb27d3
presentationframework_ni+0x2721b7
presentationframework_ni+0x271e0f
presentationframework_ni+0x271baa
clr!CallDescrWorkerInternal+0x34
clr!CallDescrWorkerWithHandler+0x6b
clr!MethodDescCallSite::CallTargetWorker+0x152
clr!RunMain+0x1aa
clr!Assembly::ExecuteMainMethod+0x124
clr!SystemDomain::ExecuteMainMethod+0x614
clr!ExecuteEXE+0x4c
clr!_CorExeMainInternal+0xdc
clr!_CorExeMain+0x4d
mscoreei!_CorExeMain+0x10a
mscoree!ShellShim__CorExeMain+0x7d
mscoree!_CorExeMain_Exported+0x8
kernel32!BaseThreadInitThunk+0xe
ntdll!__RtlUserThreadStart+0x72
ntdll!_RtlUserThreadStart+0x1b
当非托管组件发生故障时,我们如何防止这种情况并强制应用程序立即崩溃?
【问题讨论】:
-
CrashRpt 是一个 C++ 崩溃报告库。它是如何连接到 .Net 代码中以捕获托管异常的?您能否举例说明何时从 .Net 调用非托管代码并且它不会干扰
AccessViolationException? -
@ChrisO'Neill “它是如何连接到 .Net 代码中以捕获托管异常的?”它实际上并没有钩住任何托管异常。它仅捕获非托管异常。每当不使用 BeginInvoke 时,它都不会干扰。因此,只需从上面的 sn-p 中删除第一行和最后一行,作为一个简单的示例。
-
嗯,不,它也捕获托管异常。这就是您获得堆栈跟踪的方式。不好。这个库只是你想要完成的一个包 o' 字节。您需要一个调试器来可靠地检测具有支持处理程序的非托管异常。存在,您需要使用DebugDiag utility。也许ClrMD library 有用,我还没玩够。
-
所以,主进程(CrashRpt 实际挂钩的那个)是非托管代码,大概是 C++。这个过程调用一个.Net库,然后使用
BeginInvoke()调用一些非托管代码? -
@ChrisO'Neill 主要进程是 .NET,它调用 C++ 库来安装崩溃处理程序。进程(或其他加载的 .NET 程序集)随后可以调用非托管代码,或者在这种情况下,通过向非托管控件发送消息来调用非托管函数。
标签: .net exception-handling crash crash-reports