可以将信号处理后的C程序继续执行?(Can a C program continue executi

2019-07-18 00:37发布

我在信号到C处理在新的Unix和我一直在寻找它的一些教程(纯粹出于兴趣)。

我的问题是,是否有可能继续过去点的节目,其中一个信号进行处理的执行?

据我所知,信号处理功能确实清除但在异常处理(如在C ++)的精神,有可能是该信号以相同的方式和程序继续运行正常处理?

目前catch进入无限循环(可能的方式退出将调用exit(1)

我打算将是b被分配1和用于该程序正常完成(如果可能的话当然)。

这里是我的代码:

#include <signal.h>
#include <stdio.h>

int a = 5;
int b = 0;

void catch(int sig)
{
    printf("Caught the signal, will handle it now\n");
    b = 1;
}

int main(void)
{
    signal(SIGFPE, catch);

    int c = a / b;

    return 0;
}

此外,由于C是程序性的,怎么来的信号处理程序声明之前,后者已被执行之后实际上是所谓有问题的声明?

最后,为了使处理功能做了正确的清理,比需要在异常的情况下,被清理的所有变量需要先于函数声明,对不对?

在此先感谢您的回答,并道歉,如果上面的一些内容是非常明显的。

Answer 1:

是的,这就是信号处理程序是。 但有些信号需要为了让程序继续运行(例如SIGSEGV,SIGFPE,...)特别处理。

见手册页sigaction

根据POSIX,它忽略了不是由杀(2)产生或提高(3)SIGFPE,SIGILL或SIGSEGV信号之后的过程的行为是未定义的。 整数被零除未定义的结果。 在某些体系结构将产生SIGFPE信号。 (也将所述最负整数由-1可以生成SIGFPE。)忽略该信号可能会导致无限循环。

现在, 忽略信号,通过没有做任何事情,以防止它发生(再次)。 您需要在信号处理程序的执行上下文和手动修复它,这涉及到覆盖一些寄存器。

如果在其中sa_flags指定SA_SIGINFO,然后sa_sigaction(而不是sa_handler)指定为正负号的信号处理功能。 该函数接收信号编号作为第一个参数,一个指向siginfo_t作为第二个参数和一个指向ucontext_t(转换为void *)作为其第三个参数。 (通常,处理函数不作任何使用第三个参数。见的getContext(2)有关ucontext_t进一步的信息。)

上下文允许访问寄存器,在故障发生时,需要修改,允许程序继续进行。 看到这个LKML职位 。 由于有提到, siglongjmp也可能是一种选择。 该帖子还提供了处理错误相当重用的解决方案,而无需进行变量的全局等:

因为你处理它youself,你有你想要的任何灵活性的错误处理。 例如,可以使故障处理程序跳转到像这样的东西你的功能有些指定点:

 __label__ error_handler;   
 __asm__("divl %2"      
         :"=a" (low), "=d" (high)       
         :"g" (divisor), "c" (&&error_handler))     
 ... do normal cases ...

 error_handler:     
     ... check against zero division or overflow, so  whatever you want to ..

然后,你的SIGFPE处理程序只需要像做

context.eip = context.ecx;



Answer 2:

在一般情况下,是的,执行处理程序返回后继续。 但是,如果信号是由硬件错误引起的 (如浮点异常或分段错误),你有没有撤消的错误的方式,所以你的程序将被终止无关。

换句话说,你有信号和事情,导致信号之间进行区分。 通过自身的信号是完全正常和handlable,但他们并不总是让你修正导致信号错误

(有些信号是特殊的,比如ABRT和停止,因为即使你只是手动提出这样的信号与感测kill ,你仍然不能“阻止它的作用。”当然KILL甚至不能在所有的处理。 )



Answer 3:

如果你知道你在做什么,你可以设置指令指针违规的指令后,正确地指出。 下面是我在x86(32位和64位)的例子。 在家里或在真正的产品不要轻易尝试!

#define _GNU_SOURCE /* Bring REG_XXX names from /usr/include/sys/ucontext.h */

#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ucontext.h>

static void sigaction_segv(int signal, siginfo_t *si, void *arg)
{
    ucontext_t *ctx = (ucontext_t *)arg;

    /* We are on linux x86, the returning IP is stored in RIP (64bit) or EIP (32bit).
       In this example, the length of the offending instruction is 6 bytes.
       So we skip the offender ! */
    #if __WORDSIZE == 64
        printf("Caught SIGSEGV, addr %p, RIP 0x%lx\n", si->si_addr, ctx->uc_mcontext.gregs[REG_RIP]);
        ctx->uc_mcontext.gregs[REG_RIP] += 6;
    #else
        printf("Caught SIGSEGV, addr %p, EIP 0x%x\n", si->si_addr, ctx->uc_mcontext.gregs[REG_EIP]);
        ctx->uc_mcontext.gregs[REG_EIP] += 6;
    #endif
}

int main(void)
{
    struct sigaction sa;

    memset(&sa, 0, sizeof(sa));
    sigemptyset(&sa.sa_mask);
    sa.sa_sigaction = sigaction_segv;
    sa.sa_flags = SA_SIGINFO;
    sigaction(SIGSEGV, &sa, NULL);

    /* Generate a seg fault */
    *(int *)NULL = 0;

    printf("Back to normal execution.\n");

    return 0;
}


文章来源: Can a C program continue execution after a signal is handled?
标签: c signals