C++ 中的崩溃恢复
Posted
技术标签:
【中文标题】C++ 中的崩溃恢复【英文标题】:Crash recovery in C++ 【发布时间】:2014-01-18 03:05:46 【问题描述】:我有一个在 Linux 环境中用 C++ 编写的应用程序。应用程序在运行时动态加载库(共享对象)。 (应用程序获取用户命令,它会执行逻辑来动态加载所需的共享库。)
在共享库发生崩溃或段错误时,有什么方法可以防止应用程序崩溃退出?
我希望我的应用程序处于活动状态并向用户报告崩溃。
【问题讨论】:
cpp 是 C 预处理器。 C++ 是语言。 它是一个什么样的应用程序?它有多重要?告诉我们更多信息! 【参考方案1】:作为Itwasntpete answered,您可以设置(使用sigaction(2) 与 SA_SIGINFO
,不要使用signal(2)!)SIGSEGV
的信号处理程序。不过,请先仔细阅读signal(7)。
请注意,如果您想完全捕获SIGSEGV
(或其他异步信号,如SIGBUS
、SIGILL
、SIGFPE
等...)并继续处理,这很棘手,而且是特定于机器的。如果您从您的SIGSEGV
明确返回,那么机器状态保持不变,并且执行返回到触发SIGSEGV
的机器指令,该指令将重新触发ad infinitum(您是陷入无限循环)。
因此,为了能够继续执行,您不应该从信号处理程序返回,或者在其中使用siglongjmp(3) 跳转到先前使用sigsetjmp(3) 注册的状态,或者更改机器状态。要更改机器状态,您可以使用mmap(2) 和相关调用更改address space,或者您可以使用作为第三个参数传递给您的处理程序的ucontext_t*
更改一些[保存的] 处理器寄存器,并查询详细信息使用作为第二个参数传递的siginfo_t*
的信号信息。如何做到这一点是系统特定的(取决于操作系统和处理器)并且很棘手。
如果您想从信号处理程序中显示一个不错的回溯,请考虑使用例如libbacktrace 来自最近的 GCC 源球。 (如果程序和插件都使用调试信息编译,例如使用gcc -O -g
,它会更好地工作)
请注意,signal(7) 明确表示只有 异步信号安全函数 可以(直接或间接)从信号处理程序中调用。所以原则上,禁止从信号处理程序调用malloc
、::operator new
(大多数C++ containers!!)或printf
是被禁止的,而且是不明智的。但是,如果您只调用 libbacktrace
函数,然后从信号处理程序中调用 _exit(2),这通常(但原则上并非总是)有效。
如果您希望您的应用程序报告错误并保持活动状态(例如,如果您的应用程序是服务器,则能够继续处理大量请求),这可能会非常棘手(有时不可能的)。例如,如果插件错误到有corrupted the heap,你应该清理混乱(这并不总是可能的)......在某些情况下,我想唯一要做的就是重新启动应用程序(例如,通过从信号处理程序内部调用execve(2))。 Application checkpointing 技术可能是相关的:您可以将应用程序设计为定期检查点并从最新保存的状态重新启动...
一般可靠的崩溃恢复确实很困难,特别是对于 C++ 软件。你需要了解很多实现细节。完全使用free software 有很大帮助:您可以研究所有库中的细节(甚至libstdc++
和libc
:您可能需要了解malloc
的实现内部...)。
我什至不确定这是插件的正确方法。您也许可以考虑帮助插件开发人员,例如通过明确一些定义明确的应用程序特定编码规则(或programming style)并可能开发一些 GCC 编译器扩展,例如使用MELT 在插件编译时检查其中一些。
【讨论】:
【参考方案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
,而且可能还应该被捕捉到 SIGILL
、SIGFPE
... 取决于您的应用程序。
【讨论】:
效果如何取决于导致分段错误的损坏的性质。此外,从技术上讲,您的信号处理程序不应调用标准 I/O 函数。由于exit()
运行atexit()
处理程序之类的东西,它也可能不是完全安全的。尽管如此,你的建议是做什么的核心。
请注意,signal(2) 已过时。它的手册页说“避免使用它:改用sigaction(2)”以上是关于C++ 中的崩溃恢复的主要内容,如果未能解决你的问题,请参考以下文章
北亚数据恢复昆腾系列存储服务器StorNext文件系统RAID中的2块硬盘先后故障离线,RAID崩溃的数据恢复案例
服务器数据恢复raid损坏导致戴尔某型号服务器崩溃的数据恢复案例
服务器数据恢复raid5崩溃导致lvm信息和VXFS文件系统损坏的数据恢复案例