jmp_buf functjmp;
void sigsegv_handler(int sig) {
sio_printf("Caught sigsegv!\n");
siglongjmp(functjmp, 2);
return;
}
void foo(unsigned val) {
assert(0);
sio_printf("entered!\n");
}
int main() {
struct sigaction action;
action.sa_handler = sigsegv_handler;
sigemptyset(&action.sa_mask); /* Block sigs of type being handled */
sigaddset(&action.sa_mask, SIGSEGV);
action.sa_flags = SA_RESTART; /* Restart syscalls if possible */
if (sigaction(SIGSEGV, &action, NULL) < 0) {
sio_fprintf(stderr, "handler error!\n");
}
sigset_t prev_mask;
sigprocmask(SIG_BLOCK, NULL, &prev_mask);
if (sigsetjmp(functjmp, 0) == 0) {
foo(*(unsigned *)0x8);
} {
sigprocmask(SIG_BLOCK, &prev_mask, NULL);
sio_printf("jump handled!\n");
foo(*(unsigned *)0x8);
}
sio_fprintf(stderr, "how did it come here?!\n");
}
我一直在使用 gdb 调试此代码,但我无法弄清楚为什么程序不会使用我自己的处理程序处理第二个 SIGSEGV 信号(假设程序没有接收或发送其他信号)?任何带有 sio 前缀的函数都是 stdio 对应函数的异步安全变体。 目前,我推测这与我在从信号处理程序返回的概念中缺少的一些东西有关,而 longjmp 根本不这样做。
最佳答案
简短回答:对于 C 程序,通常无法在 SIGSEGV 之后恢复。使用 C++ 可能会取得更多进展。
长答案:请参阅 Coming back to life after Segmentation Violation 中的讨论
假设可以承担未定义行为的风险:
可以重新启用 SEGV。核心问题是,在信号处理程序期间,代码显式阻止 SEGV 信号被触发(使用 sigaddset)。此外,(信号处理程序的)默认行为是在信号处理期间,相同的信号处理将被推迟,直到信号处理程序返回。在OP代码中,信号处理程序永远不会返回(因为siglongjmp)
这两个问题都可以通过更改原始代码来解决。
// Make sure all attributes are NULL.
struct sigaction action = {} ;
action.sa_handler = sigsegv_handler;
sigemptyset(&action.sa_mask); /* Block sigs of type being handled */
// Not Needed:: sigaddset(&action.sa_mask, SIGSEGV);
// Add SA_NODEFER to disable the deferred processing of SIGSEGV.
action.sa_flags = SA_RESTART | SA_NODEFER ; /* Restart syscalls if possible */
// rest of code here
if (sigaction(SIGSEGV, &action, NULL) < 0) {
sio_fprintf(stderr, "handler error!\n");
}
...
关于c - 为什么我的信号处理程序在这里没有被调用多次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59596577/