Exception handling CLR是如何识别“a”的;损坏状态异常“;?

Exception handling CLR是如何识别“a”的;损坏状态异常“;?,exception-handling,clr,Exception Handling,Clr,背景 我们的应用程序调用一个混合模式程序集,该程序集的非托管代码中存在一个已知错误,导致抛出AccessViolationException 我们的目标是捕获AV异常,将其包装,并在终止应用程序之前抛出一个新的异常,该异常将在堆栈的更高层被捕获并记录 问题 我们的代码没有按我们预期的那样运行。。。我们用来包装AV异常的“普通”异常的行为就像CSE一样,没有被我们的顶级异常处理程序捕获。相反,它冒泡到操作系统,从而终止了进程。这只在Windows事件日志中留下了一条混乱的日志消息,表明Invali

背景

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

    catch (AccessViolationException ex)
你犯了一个简单的错误,否则可能说明了感染CSE的巨大危险。问题是,您还必须知道要捕获哪个特定的CSE。他们不止一个

是的,这场灾难始于操作系统中的AVE。但并没有保持这种方式,CLR对低64KB内存中的访问触发的AVE有一个特殊规则。它将它们转换为
NullReferenceException
。你没抓到。修正:

    catch (NullReferenceException ex)

现在它工作正常。

谢谢Hans-有趣的信息。。。但是我的机器上没有相同的行为(例如,调用Marshal.StructureToPtr()时肯定会抛出一个AVE)。在最初的示例中,我感兴趣的是为什么它没有捕获RunTest()中的invalidoOperationException。CLR不会将其呈现给catch块,因为它认为它是CSE。如果您将HPCSE属性添加到RunTest,它将按照设计吞下InvalidOperationException。不,它肯定是一个引发的NullReferenceException。只需将其更改为
var ptr=new IntPtr(65536)
获取AccessViolationException。不在我的计算机上:0)…我附上了一个屏幕截图来演示。无论如何,accessViolation()中的catch只能是catch(Exception ex)。我的问题是,为什么你不能在RunTest()中捕捉到InvalidOperationException?我无法重新编程,但没有使用MSTest runner,而是使用了控制台模式的应用程序。请确保在“调试+异常”对话框中关闭了抛出的复选框。