【问题标题】:How to catch SIGBUS error?如何捕捉 SIGBUS 错误?
【发布时间】:2015-01-24 17:57:50
【问题描述】:

我试图捕捉只读存储器上的错误但无法做到? 如果我处理了错误,那么它程序可以继续或唯一的选项是退出/中止?

#include<iostream>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
char * F00()
{
        char *s2="ab";
        return s2;
}

void InvalidMem()
{
                (F00())[0]='l';
}



void
termination_handler (int signum)
{
        fprintf(stderr,"BUS error");
}

int
main(int argc, char **argv)
{
        signal (SIGBUS, termination_handler);

        InvalidMem();

        for(int i = 0; i < 10; ++i)
                std::cout<<" L " ;

        return 0;
}

【问题讨论】:

  • 从哪一点继续?
  • 尝试从如此严重的崩溃中继续是可能的,但是您怎么知道程序处于可以安全继续的状态?简而言之:你不能。与其尝试“捕捉”崩溃并尝试继续,不如找到崩溃的根本原因并解决该问题,而不是试图忽略它。
  • Joachim,我同意你关于状态的观点,但这是否意味着如果我捕捉到一个信号,那么程序可以从导致信号提升的点继续。
  • 如果我添加以下内容:信号(SIGSEGV,termination_handler);然后它陷入无限循环并总是打印 BUS 错误。
  • 就像我说的,这是可能,但从来没有是个好主意!

标签: c++ linux signals


【解决方案1】:

SIGBUS 表示您正在访问未对齐的地址,SIGSEGV 表示您正在访问您“不应该”的地址(无效地址,或写入只读内存 - 在某些情况下内存可以是只写的,并且从这样的内存中读取也会导致 SIGSEGV)。

由于处理器并不真正知道当您最终进入信号处理程序时它处于什么状态,因此在这些情况下通常不可能仅从信号处理程序本身继续。相反,典型的方法是使用setjmp 和longjmp 来“恢复到已知点”。这可能是您的代码的“主循环”,或某个错误恢复点。

所以,是这样的:

 jmp_buf reset;

 int termination_handler(int signum)
 {
     longjmp(reset, 1);
 }

 int main()
 {
    if (setjmp(reset) != 0)
    {
        printf("We got back from signal handler")
        ...
    }
    signal (SIGBUS, termination_handler);
    ...
    return 0;
 }

应该注意的是,如果在执行错误(如总线故障或地址故障)之后“继续”,您可能会遇到一些严重的麻烦 - 例如:

// At global level:
  some_lock lock;

// in some function. 
  ....
  lock->take();
  some code that crashes;
  lock->release();

所以,现在锁已被持有,并且永远不会被释放...下次您需要获取锁时代码可能会挂起...

【讨论】:

  • 我同意你的观点,但我想知道这里的所有可能性。
  • “所有可能性”的范围很广,在我所知道的所有操作系统中,当前一个操作无效时,只要从信号处理程序返回,操作系统就会终止进程。所以你需要“退出信号处理程序,不返回”——这有点像垄断,“直接入狱,不要通过 go”。
猜你喜欢
  • 2010-12-06
  • 2021-12-06
  • 1970-01-01
  • 2010-12-05
  • 2017-09-22
  • 2016-06-02
  • 2011-08-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多