在单独的线程上捕获AccessViolationException

时间:2017-03-28 17:55:40

标签: c# pinvoke

我正在调用可能不稳定的本地库,我想确保我的C#应用​​程序可以在潜在的AccessViolationException中存活。我找到了一种方法,可以在<legacyCorruptedStateExceptionsPolicy enabled="true" />中使用App.config来捕获异常。由于崩溃发生在我不关心的单独线程上(我不在乎它是否会死),保持我的应用程序运行是否安全?如果没有,是否有任何机制允许我沙箱化本机代码以防止崩溃?

我不只是想记录崩溃,我真的想要生存AccessViolationException

我已经尝试在另一个AppDomain中执行代码,但由于它在同一个进程中运行,所以它并没有真正帮助。我还有一个备份解决方案,它依赖于一个新的Process和一个IPC通道进行通信,但这很难维护和调试。如果我能在主要过程中做到这一点,那将会简化很多事情。

如果要创建要测试的环境,只需使用导致崩溃的单个函数创建一个简单的Win32库(AccessViolationException)。

C标题:

__declspec(dllexport) void do_crash();

C来源:

void do_crash()
{
    int *b = NULL;
    int c = b[3000];
}

C#来源:

[DllImport("CrashLib.dll", EntryPoint = "do_crash")]
extern static void DoCrash();

static void Main(string[] args)
{   
    ExecuteSandboxed(delegate
    {
        DoCrash();
    });

    // Even if there's a AccessViolationException, I can keep going

    Console.ReadLine();
}

private static void ExecuteSandboxed(Action action)
{
    try
    {
        Task.Run(action).Wait();
        Console.WriteLine("Success");
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

1 个答案:

答案 0 :(得分:0)

坚果壳中的异常

异常背后的基本思想是说&#34;这不能做到&#34;并防止应用程序继续处于损坏状态。当引发异常时,它通常允许应用程序在当前情况下继续执行。这是通过倒回调用堆栈并查找异常处理程序(try-catch块)来完成的。

例外情况可能来自三个主要来源:

  • 应用程序本身(使用throw ...
  • 操作系统 - FileNotFoundException
  • 等例外情况
  • CPU - DivideByZeroException之类的异常(由于ALU无法执行此类计算而引发)

到目前为止最可怕的例外是由CPU引发的例外,因为它们可以使它处于无效状态。

此外,例外可分为三类:

  • 无效操作 - 当应用程序尝试执行无效操作时,抛出此类异常。诸如访问不存在的文件,除以零等操作。
  • 无效的线程状态 - 当给定线程的状态被破坏时抛出此类异常。运行时堆栈损坏等情况可能是原因。
  • 无效的进程(应用程序)状态 - 当整个应用程序处于无效状态时,抛出此类异常。耗尽内存就是一个很好的例子。

每种异常都比以前更严重。第一个将终止当前过程并启动调用堆栈倒带。第二个将终止整个线程。最后一个将终止整个申请。

注意:终止过程涉及的范围更广,例外并没有真正分为三种。

了解AccessViolationException

现在我们对异常有了基本的了解,我们可以预测AccessViolationException将离开我们的应用程序的状态。

首先,谁抛出异常?这是一个棘手的问题*但实际上,当它意识到地址尚未分配给进程时,操作系统会抛出它。

它是什么类型的异常?由于异常与线程的状态和应用程序无关;我们只是试图访问&#34;不存在&#34;内存(很像我们可能会尝试访问不存在的文件)。这显然是Invalid Operation例外。

AccessViolationException是来自操作系统的无效操作异常。现在我们知道我们可以安全地继续执行正弦我们知道我们确实没有使CPU状态无效,也不是应用程序状态,也不是Thread状态;我们只是尝试了非法的事情。