背景
我们的应用程序调用混合模式程序集,该程序集在其非托管代码中存在已知错误,导致抛出AccessViolationException。
我们的目标是捕获AV异常,将其包装起来,并在我们终止应用程序之前抛出一个新的异常,该异常会在堆栈中被捕获并记录下来。
问题
我们的代码没有像我们预期的那样行事......' vanilla'我们用来包装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? (......我假设在两种情况下都有相同的机制)
更新: 汉斯'回答,这是一个屏幕截图,显示了抛出和捕获的AV异常:
答案 0 :(得分:1)
catch (AccessViolationException ex)
你犯了一个简单的错误,否则可能说明了捕捉CSE的相当大的危害。问题是你还必须知道要捕获哪个特定的CSE。它们不止一个。
是的,这个不幸事件在操作系统中作为AVE启动。但是没有保持这种状态,CLR对AVE有一个特殊的规则,它由较低64KB内存中的访问触发。它将它们变成NullReferenceException
。哪个你没抓到。修正:
catch (NullReferenceException ex)
现在工作正常。