6

我正在一个图书馆工作,我将各种任务交给一些第三方图书馆,这些图书馆做一些相对粗略或危险的特定于平台的工作。(具体来说,我正在编写一个数学函数解析器,它调用 JIT 编译器,如 LLVM 或 libjit,以构建机器代码。)在实践中,这些第三方库有崩溃的趋势(部分原因是我的错,当然,但我仍然想要一些保险)。

那么,我希望能够非常优雅地处理一项可怕的工作——SIGSEGV、SIGILL 等——而不会降低我的其余代码(或调用我的库函数的用户的代码)。需要明确的是,我不关心该特定工作是否可以继续(我不会尝试修复崩溃条件),我也不真正关心此类崩溃后对象的状态(我会丢弃如果发生崩溃,请立即使用它们)。我只想能够检测到发生了崩溃,阻止崩溃退出整个进程,停止调用任何崩溃的内容,并恢复执行。

(对于更多的上下文,目前的代码是一个 for 循环,测试每个可用的 JIT 编译器。其中一些编译器可能会崩溃。如果他们这样做,我只想执行continue;并继续测试另一个编译器。 )

目前,我有一个signal()基于 - 的实现非常可怕地失败了;当然,longjmp()超出信号处理程序是未定义的行为,并且信号处理程序几乎预计会以exit()or结尾terminate()。只是将代码扔到另一个线程中本身并没有帮助,至少到目前为止我已经测试过它的方式。我也无法破解使用 C++ 异常来完成这项工作的方法。

那么,将一组特定指令/线程/作业与崩溃隔离的最佳方法是什么?

4

4 回答 4

11

产生一个新进程。

于 2010-08-24T15:20:03.710 回答
5

当工作成功时,你会收集什么输出?

我问是因为如果输出是低带宽,我会很想在自己的进程中运行每个作业。

您启动的这些崩溃作业中的每一个都极有可能破坏进程中其他地方使用的内存。

流程提供了最好的保护。

于 2010-08-24T15:20:46.453 回答
1

流程提供了最好的保护,但您可能无法做到这一点。

如果您的线程的入口点是您编写的函数(例如,ThreadProc在 Windows 世界中),那么您可以将它们包装在try{...}catch(...)块中。如果您想传达发生了异常的信息,则可以将特定的错误代码传达回主线程或使用其他一些机制。如果您不仅要记录发生的异常,还要记录该异常是什么,那么您需要捕获特定的异常类型并从中提取诊断信息,以便与主线程进行通信。翼:

int my_tempermental_thread()
{
  try
  {
    // ... magic happens ...
    return 0;
  }
  catch( const std::exception& ex )
  {
    // ... or maybe it doesn't ...
    string reason = ex.what();
    tell_main_thread_what_went_wong(reason);
    return 1;
  }
  catch( ... )
  {
    // ... definitely not magical happenings here ...
    tell_main_thread_what_went_wrong("uh, something bad and undefined");
    return 2;
  }
}

请注意,如果您采用这种方式,当异常确实发生时,您会冒着占用主机进程的风险。你说你不是在试图纠正问题,但是你怎么知道恶性线程没有吃掉你的堆栈?Catch-and-ignore 是一种创建可怕的令人困惑的错误的好方法。

于 2010-08-24T17:03:56.787 回答
0

在 Windows 上,您可能可以VirtualProtect(YourMemory, PAGE_READONLY)在调用不受信任的代码时使用。任何修改此内存的尝试都会导致结构化异常。您可以安全地捕捉到这一点并继续执行。但是,该库分配的内存当然会泄漏,其他资源也是如此。Linux 等效项是mprotect(YorMemory, PROT_READ),它会导致 SEGV。

于 2010-08-25T09:34:44.217 回答