CLR如何识别“腐败状态异常”?

时间:2015-01-15 16:58:05

标签: exception-handling clr

背景

我们的应用程序调用混合模式程序集,该程序集在其非托管代码中存在已知错误,导致抛出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异常:screenshot

1 个答案:

答案 0 :(得分:1)

    catch (AccessViolationException ex)

你犯了一个简单的错误,否则可能说明了捕捉CSE的相当大的危害。问题是你还必须知道要捕获哪个特定的CSE。它们不止一个。

是的,这个不幸事件在操作系统中作为AVE启动。但是没有保持这种状态,CLR对AVE有一个特殊的规则,它由较低64KB内存中的访问触发。它将它们变成NullReferenceException。哪个你没抓到。修正:

    catch (NullReferenceException ex)

现在工作正常。