崩溃后程序保持运行状态而不退出

参考:

http://blog.csdn.net/langresser_king/article/details/8288195


http://stackoverflow.com/questions/2663456/how-to-write-a-signal-handler-to-catch-sigsegv


When your signal handler returns (assuming it doesn't call exit or longjmp or something that prevents it from actually returning), the code will continue at the point the signal occurred, reexecuting the same instruction. Since at this point, the memory protection has not been changed, it will just throw the signal again, and you'll be back in your signal handler in an infinite loop.

So to make it work, you have to call mprotect in the signal handler. Unfortunately, as Steven Schansker notes, mprotect is not async-safe, so you can't safely call it from the signal handler. So, as far as POSIX is concerned, you're screwed.

Fortunately on most implementations (all modern UNIX and Linux variants as far as I know), mprotect is a system call, so is safe to call from within a signal handler, so you can do most of what you want. The problem is that if you want to change the protections back after the read, you'll have to do that in the main program after the read.

Another possibility is to do something with the third argument to the signal handler, which points at an OS and arch specific structure that contains info about where the signal occurred. On Linux, this is a ucontext structure, which contains machine-specific info about the $PC address and other register contents where the signal occurred. If you modify this, you change where the signal handler will return to, so you can change the $PC to be just after the faulting instruction so it won't re-execute after the handler returns. This is very tricky to get right (and non-portable too).

The ucontext structure is defined in <ucontext.h>. Within the ucontext the field uc_mcontext contains the machine context, and within that, the array gregs contains the general register context. So in your signal handler:

ucontext *u = (ucontext *)unused;
unsigned char *pc = (unsigned char *)u->uc_mcontext.gregs[REG_RIP];
will give you the pc where the exception occurred. You can read it to figure out what instruction it was that faulted, and do something different.

As far as the portability of calling mprotect in the signal handler is concerned, any system that follows either the SVID spec or the BSD4 spec should be safe -- they allow calling any system call (anything in section 2 of the manual) in a signal handler.


参考《unix高级环境编程》

while(1)
{
        registerExceptionCatcher();
        if(sigsetjmp(jmpbuf, 1))
        {
            __DEBUG_LOG("jump back here #594");
            registerExceptionCatcher();
            continue;
        }
        canjump = 1;

        // 可能崩溃的代码
        unregisterExceptionCatcher();     
}

static void sighandler (int);
static sigjmp_buf jmpbuf;
static volatile sig_atomic_t canjump;

static void sighandler(int signum)
{
    if (0 == canjump)
    {
        __DEBUG_LOG("canjump 0");
        return;
    }

    struct tm *t = NULL;
    time_t stm;
    time(&stm);
    t = localtime(&stm);
    char timeBuf[64] = {0};
    if(t != NULL)
    {
        snprintf(timeBuf,50,"%s %d-%02d-%02d %02d:%02d",t->tm_zone,t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min);
    }
    __DEBUG_LOG("[crash] sighandler signum:%d, %s", signum, timeBuf);

    canjump = 0;
    siglongjmp(jmpbuf, 1); /* jump back to the line before crash */
}

static struct sigaction act, oact;
void registerExceptionCatcher()
{
    memset(&act, 0, sizeof(sigaction));
    act._u._sa_handler = sighandler;
    act.sa_flags = SA_RESETHAND;
    sigemptyset(&act.sa_mask);

    sigaction(SIGSEGV, &act, &oact);
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值