如何测试 AccessViolationException 的处理方式

18
我需要编写一个测试来验证我的代码能否处理AccessViolationException(或其他WIN32损坏状态异常 - CSE),这通常是在不安全的上下文中调用第三方库引起的。所有这些都应该在.NET 4.0上使用C#完成。
我发现了这个相关问题如何处理AccessViolationException和这篇相关文章http://dotnetslackers.com/articles/net/All-about-Corrupted-State-Exceptions-in-NET4.aspx,其中解释了如何捕获这些CSE及其背景。
因此,我想在测试中触发WIN32 CSE,以确保正确处理我的应用程序。类似于:
要测试的一些示例类:
public class MyExceptionHandler
{
    [HandleProcessCorruptedStateExceptions]
    public void HandleCorruptedStateException()
    {
        try
        {
             //Force genuine unsafe AccessViolationException
             //not just a throw new AccessViolationException
        }
        catch(Exception e)
        {
             //Log/cleanup/other
        }
    }

    public void DoesNotHandleCorruptedStateException()
    {
        try
        {
             //Force genuine unsafe AccessViolationException
             //not just a throw new AccessViolationException
        }
        catch (Exception e)
        {
            //Log/cleanup/other
        }
    }
}

一次测试:

class MyTest
{
    [Test]
    public void ShouldVerifyThatAnAccessViolationExceptionIsHandledCorrectly()
    {
        var handler = new MyExceptionHandler();

        Assert.DoesNotThrow(() => handler.HandleCorruptedStateException());
    }

    [Test]
    public void ShouldVerifyThatAnAccessViolationExceptionIsNotHandledCorrectly()
    {
        var handler = new MyExceptionHandler();

        Assert.Throws<AccessViolationException>(() => handler.DoesNotHandleCorruptedStateException());
    }
}

有没有人有什么建议,可以在不费太多力气的情况下实现这个目标(例如编写一个不安全的库来引发此异常)。

敬礼

更新:为了匹配我的最终解决方案,感谢JaredPar。

public class MyExceptionHandler
{
    [HandleProcessCorruptedStateExceptions]
    public void HandleCorruptedStateException()
    {
        try
        {
            var ptr = new IntPtr(42);
            Marshal.StructureToPtr(42, ptr, true);
        }
        catch(Exception e)
        {
             //Log/cleanup/other
        }
    }

    public void DoesNotHandleCorruptedStateException()
    {
        try
        {
            var ptr = new IntPtr(42);
            Marshal.StructureToPtr(42, ptr, true);
        }
        catch (Exception e)
        {
            //Log/cleanup/other
        }
    }
}

提示: 要手动验证此内容,请使用一个简单的控制台应用程序,在命令行中执行:

TIP: 要手动验证此内容,请使用一个简单的控制台应用程序,在命令行中执行:

class Program
{
    static void Main(string[] args)
    {
        var handler = new MyExceptionHandler();

        if (args.Length > 1)
        {
            handler.HandleCorruptedStateException();
        }
        else
        {
            handler.DoesNotHandleCorruptedStateException();
        }
    }
}
2个回答

29

尝试以下方法

var ptr = new IntPtr(42);
Marshal.StructureToPtr(42, ptr, true);

按照CLI规范,这并不保证会抛出AccessViolationException异常,但在我所知道的所有平台上都会抛出。


谢谢,但这不会生成CSE,只会生成ArgumentNullException。必须是真正的Win32 CSE,如果在try catch中未处理并标记为[HandleProcessCorruptedStateExceptions]属性等,则会导致应用程序崩溃,如文章所述。 - Christian Mikkelsen
我改口了,这个确实管用 :-D。我在测试中犯了一个错误(典型的)。非常感谢你 :)。 - Christian Mikkelsen

2
    private static unsafe void AccessViolation()
    {
        int* p = (int*)0xFF004324;
        int q = *p;
    }

已删除不安全的写入。从该地址读取仍应生成AccessViolationException(除非巧合地在您的地址空间内)。


OP正在寻求一个不涉及不安全代码的C#答案。 - JaredPar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接