【问题标题】:cannot catch segmentation fault second time第二次无法捕获分段错误
【发布时间】:2021-11-15 07:16:49
【问题描述】:

发生分段错误时,我正在尝试重新启动程序。

我有以下最少的可重现代码:-

#include <csignal>
#include <unistd.h>
#include <iostream>

int app();

void ouch(int sig) {
    std::cout << "got signal " << sig << std::endl;
    exit(app());
}

struct L { int l; };
static int i = 0;

int app() {
    L *l= nullptr;
    while(1) {
        std::cout << ++i << std::endl;
        sleep(1);
        std::cout << l->l << std::endl; //crash
        std::cout << "Ok" << std::endl;
    }
}

int main() {
    struct sigaction act;
    act.sa_handler = ouch;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    sigaction(SIGKILL, &act, 0);
    sigaction(SIGSEGV, &act, 0);
    return app();
}

它第一次成功捕获 sigsegv,但在打印 2 后,它显示分段错误(核心转储)

1
got signal 11
2
zsh: segmentation fault (core dumped)  ./a.out

在 ArchLinux 上使用 clang 12.0.1 和 gcc 11.1.0 测试

这是操作系统特有的行为还是我的代码有问题

【问题讨论】:

  • 您似乎不明白使用什么信号处理程序。如果信号是从信号处理程序发出的,那就不好了。
  • Why can't I ignore SIGSEGV signal?中的可能补救措施
  • 试图从段错误中恢复几乎总是一个非常糟糕的主意。它并非设计为可恢复的错误,它通常表示无法在运行时修复的逻辑错误。
  • 你真的应该换个角度思考,并对段错误表示感谢。这意味着您的程序中存在需要解决的错误。在解决这个问题的根本原因之前不要添加新代码。
  • 你可以siglongjmp尝试回到程序中的某个已知点,但是全局状态可能会混乱,你也可能会泄漏内存或其他资源。或者您可以exec() 完全从头开始。

标签: c++ linux segmentation-fault


【解决方案1】:

问题在于,当您通过从ouch() 内部调用exit(app()) 重新启动程序时,从技术上讲,您仍然在信号处理程序内部。信号处理程序被阻塞,直到您从它返回。由于您永远不会回来,因此您无法捕获第二个 SIGSEGV。

如果你有一个 SIGSEGV,那么确实发生了一些非常糟糕的事情,并且不能保证你可以通过再次调用 app() 来“重新启动”进程。 处理此问题的最佳解决方案是让另一个程序启动您的程序,并在它崩溃时重新启动它。有关如何处理此问题的一些建议,请参阅 this ServerFault question

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-30
    • 2015-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-04
    • 1970-01-01
    相关资源
    最近更新 更多