【发布时间】:2015-01-15 16:58:04
【问题描述】:
背景
我们的应用程序调用一个混合模式程序集,该程序集在其非托管代码中有一个已知错误,会导致抛出 AccessViolationException。
我们的目标是在终止应用程序之前捕获 AV 异常,将其包装,然后抛出一个新异常,该异常将在堆栈的更高位置被捕获并记录下来。
问题
我们的代码没有像我们预期的那样运行......我们用来包装 AV 异常的“普通”异常表现得就像是 CSE,并且没有被我们的顶级异常处理程序捕获.相反,它冒泡到操作系统,终止了该过程。这只会在 Windows 事件日志中留下一条令人困惑的日志消息,表明 InvalidOperationException 以某种方式设法绕过了我们所有的异常处理程序并终止了进程。
请注意,只有将 AV 异常设置为包装异常的内部异常时,才会显示此行为。
这是一个例子:
[Test]
public void RunTest()
{
try
{
ProvokeAccessViolation();
}
catch (InvalidOperationException e)
{
// We never get here!
Console.WriteLine("Log exception: " + e);
}
}
[HandleProcessCorruptedStateExceptions]
[SecurityCritical]
public static void ProvokeAccessViolation()
{
try
{
var ptr = new IntPtr(1);
const bool someValue = true;
Marshal.StructureToPtr(someValue, ptr, true); // Will throw AccessViolationException
}
catch (AccessViolationException ex)
{
Console.WriteLine("Caught AV exception: " + ex);
throw new InvalidOperationException("Wrapping AV exception", ex);
}
}
我的问题是,CLR 是如何知道将包装异常(上例中的 InvalidOperationException)视为 CSE 的?
同样,如果您只是从托管代码中抛出一个新的 AccessViolationException,为什么它不表现得像 CSE? (...我假设在这两种情况下使用相同的机制)
更新: 继 Hans 的回答之后,这里是一个显示 AV 异常被抛出和捕获的屏幕截图:
【问题讨论】: