如何在检测到 AccessViolationException 时强制应用程序崩溃
How to force an application crash when AccessViolationException is detected
我们使用自动崩溃报告工具(即 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
当非托管组件发生故障时,我们如何防止这种情况并强制应用程序立即崩溃?
试试这个:
this.Dispatcher.BeginInvoke((Action) delegate
{
User32.SendMessage(...);
}, DispatcherPriority.Input);
应用程序应该按照您希望的方式崩溃。
我见过的大多数使用匿名委托调用 Dispatcher.BeginInvoke()
的示例都使用了 Action
.
- https://richnewman.wordpress.com/2012/12/03/tutorial-asynchronous-programming-async-and-await-for-beginners/
- http://tech.pro/tutorial/800/working-with-the-wpf-dispatcher
为什么会这样?
看来 CLR 代码,方式在:
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.DispatcherOperation.InvokeImpl()
直接调用 Action
,大多数其他委托使用反射调用。
反射机制会将异常包装在TargetInvocationException
.
中
参见另一个问题进行解释。
其他不会包装异常的特殊情况委托是:
DispatcherOperationCallback
和 SendOrPostCallback
,尽管它们必须使用单个参数来调用。
this.Dispatcher.BeginInvoke(DispatcherPriority.Input,
(SendOrPostCallback)(delegate(object o)
{
throw new AccessViolationException(o.ToString());
}), "test");
获取异常后使用以下代码关闭应用程序。
Environment.Exit(1);
Exit 需要一个名为 exitcode 的参数。如果 exitcode=0 表示没有错误。提供非零退出代码以反映错误。
我们使用自动崩溃报告工具(即 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
当非托管组件发生故障时,我们如何防止这种情况并强制应用程序立即崩溃?
试试这个:
this.Dispatcher.BeginInvoke((Action) delegate
{
User32.SendMessage(...);
}, DispatcherPriority.Input);
应用程序应该按照您希望的方式崩溃。
我见过的大多数使用匿名委托调用 Dispatcher.BeginInvoke()
的示例都使用了 Action
.
- https://richnewman.wordpress.com/2012/12/03/tutorial-asynchronous-programming-async-and-await-for-beginners/
- http://tech.pro/tutorial/800/working-with-the-wpf-dispatcher
为什么会这样?
看来 CLR 代码,方式在:
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.DispatcherOperation.InvokeImpl()
直接调用 Action
,大多数其他委托使用反射调用。
反射机制会将异常包装在TargetInvocationException
.
参见
其他不会包装异常的特殊情况委托是:
DispatcherOperationCallback
和 SendOrPostCallback
,尽管它们必须使用单个参数来调用。
this.Dispatcher.BeginInvoke(DispatcherPriority.Input,
(SendOrPostCallback)(delegate(object o)
{
throw new AccessViolationException(o.ToString());
}), "test");
获取异常后使用以下代码关闭应用程序。
Environment.Exit(1);
Exit 需要一个名为 exitcode 的参数。如果 exitcode=0 表示没有错误。提供非零退出代码以反映错误。