C ++中的崩溃恢复

时间:2013-12-31 06:30:52

标签: c++ linux crash recovery

我在Linux环境中使用C ++编写了一个应用程序。该应用程序在运行时动态加载库(共享对象)。 (应用程序获取用户命令,它将执行动态加载所需共享库的逻辑。)

有没有办法阻止应用程序在共享库中发生崩溃或段错误时崩溃和退出?

我希望我的应用程序处于活动状态并向用户报告崩溃。

2 个答案:

答案 0 :(得分:2)

是的,这是可能的。 If a segfault occurs,您的计划将首先收到SIGSEGV(请参阅signal或由于信号已过时sigaction(2))。将此信号连接到处理程序允许您制作崩溃报告。

void crash(int sig) {
  cout << "report crash";
  exit(sig);
}

int main() {
  // connect signal to handler
  signal(SIGSEGV, crash);

  return 0;
}

Jonathan Leffler提到的是他的评论,这只是一个小小的建议。有一些信号不仅应该被SIGSEGV捕获,而且还可能SIGILLSIGFPE ...取决于您的应用。

答案 1 :(得分:2)

作为Itwasntpete answered你可以设置(使用sigaction(2) SA_SIGINFO,不要使用signal(2)!){{{{{{ 1}}。不过,请先仔细阅读signal(7)

请注意,如果您想完全捕获SIGSEGV(或其他异步信号,如SIGSEGVSIGBUSSIGILL等...并继续处理,则为棘手和机器特定。如果从SIGFPE清楚地返回,则机器状态保持不变,并且执行返回到已触发SIGSEGV的机器指令,该指令将无限制地重新启动无限期(你陷入无休止的循环)。

因此,为了能够继续执行,您应该不从信号处理程序返回,或者使用其中的siglongjmp(3)跳转到先前使用sigsetjmp(3)注册的状态,或者更改机器状态。要更改机器状态,您可以使用address space和相关调用更改mmap(2),或者您可以使用作为第三个参数传递的SIGSEGV更改某些[已保存]处理器寄存器,并使用作为第二个参数传递的ucontext_t*查询信号信息的详细信息。如何做到这一点是系统特定的(它取决于操作系统和处理器)和棘手。

如果你想从信号处理程序中显示一个很好的回溯,请考虑使用例如来自最近的GCC源球内的libbacktrace。 (如果程序和插件都使用调试信息进行编译,例如使用siginfo_t*

,它会更好用

请注意,signal(7)明确表示只能从信号处理程序(直接或间接)调用 async-signal-safe functions 。因此原则上禁止从信号处理程序调用{​​{1}},gcc -O -g(大多数C++ containers !!或malloc调用},这是不明智的。但是,如果您只是从信号处理程序中调用::operator new函数然后调用_exit(2),那通常会(但原则上并非总是)有效。

如果您希望应用程序报告错误并且保持活动(例如,如果您的应用程序是服务器,以便能够继续提供大量请求),那么它可能会非常棘手(有时候)不可能)。例如,如果插件有错误到达corrupted the heap,你应该清理乱七八糟的东西(这并不总是可行的)....在某些情况下,我会想象唯一要做的就是是重新启动应用程序(例如,通过从信号处理程序内部调用execve(2))。 Application checkpointing技术可能是相关的:您可以定期将应用程序设计为检查点,并从最新保存的状态重新启动...

一般来说,可靠的崩溃恢复非常困难,特别是对于C ++软件。您需要了解很多实现细节。专门使用free software有很大帮助:您可以研究所有库中的详细信息(甚至printflibbacktrace:您可能需要了解libstdc++的实施内部... )。

我甚至不确定这是插件的正确方法。您可以考虑帮助插件开发人员,例如通过阐明一些定义明确的应用程序特定的编码规则(或programming style)并可能开发一些GCC编译器扩展,例如使用MELT在插件编译时检查其中一些。