C++利用SIGSEGV信号处理实现发生segment fault后不崩溃的代码

C++代码在内存越界或线程竞争情况下很容易出现未定义行为段错误,导致程序崩溃挂掉生成coredump,但如果想让程序遇到这种情况仍然可以继续运行,不中断服务呢?这里展示了一种方法。

C++代码发生段错误后系统会抛出SIGSEGV 信号 ,之后 调用默认的信号处理函数 ,产生core文件 ,然后关闭程序。让程序不挂掉的办法就是捕获这个中断信号,调用自定义的信号处理函数,并且叠加一些代码跳转的方法。

单纯捕捉信号不做特殊处理,虽然进程仍然在,但是会一直报错阻塞主线程,程序完全不可用。

有效的做法是在发生段错误的代码之前保存程序执行上下文,信号捕捉后通过跳转函数直接跳过段错误的代码,从而达到程序继续执行的目的。

这里用到两个函数sigsetjmp和siglongjmp,前者会保存当前的信号屏蔽表 (signal mask),后者跳转的时候会恢复线程的屏蔽表。通过设置的参数传递上下文信息。

代码:

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <stdarg.h>
#include <thread>
#include <chrono>

sigjmp_buf env;

void handle_signal(int sig)
{
    printf("# handle_signal %d\n", sig);
    
    // jump to continue code point
    siglongjmp(env, 1);
}
int main(int argc,char** argv)
{
    // global register signal handle
    signal(SIGSEGV, handle_signal);

    for (int i = 0; i < 10; i++)
    {
        // save context
        int r = sigsetjmp(env, 1);
        if(r == 0)
        {
            // execute different code dynamically
            if (i % 2)
            {
                printf("execute the bad code\n");
                int* p = nullptr;
                *p = 7;
            }
            else
            {
                printf("execute the good code\n");
                int p = 7;
            }
        }
        else
        {
            // jump from signal handle
            printf("skip the bad code, i = %d\n", i);
        }
    }

    while(true)
    {
        printf("--- I am alive ---\n");
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    return 0;
}

执行结果:

execute the good code
execute the bad code
# handle_signal 11
skip the bad code, i = 1
execute the good code
execute the bad code
# handle_signal 11
skip the bad code, i = 3
execute the good code
execute the bad code
# handle_signal 11
skip the bad code, i = 5
execute the good code
execute the bad code
# handle_signal 11
skip the bad code, i = 7
execute the good code
execute the bad code
# handle_signal 11
skip the bad code, i = 9
--- I am alive ---
--- I am alive ---
--- I am alive ---
--- I am alive ---

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值