为什么我不能忽略 SIGSEGV 信号? [英] Why can't I ignore SIGSEGV signal?

查看:26
本文介绍了为什么我不能忽略 SIGSEGV 信号?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的代码,

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

int main(int argc,char ** argv)
   {
     char *p=NULL;
     signal(SIGSEGV,SIG_IGN); //Ignoring the Signal
     printf("%d",*p);
     printf("Stack Overflow"); //This has to be printed. Right?
   return 0;
    }

在执行代码时,我遇到了分段错误.我使用 SIG_IGN 忽略了信号.所以我不应该得到分段错误.对?然后,打印 '*p' 值后的 printf() 语句也必须执行.对?

While executing the code, i'm getting segmentation fault. I ignored the signal using SIG_IGN. So I shouldn't get Segmentation fault. Right? Then, the printf() statement after printing '*p' value must executed too. Right?

推荐答案

您的代码忽略了 SIGSEGV 而不是捕获它.回想一下,触发信号的指令在处理信号后重新启动.在你的情况下,处理信号没有改变任何东西,所以下一次尝试违规指令时,它会以同样的方式失败.

Your code is ignoring SIGSEGV instead of catching it. Recall that the instruction that triggered the signal is restarted after handling the signal. In your case, handling the signal didn't change anything so the next time round the offending instruction is tried, it fails the same way.

如果你想捕捉信号改变这个

If you intend to catch the signal change this

signal(SIGSEGV, SIG_IGN);

到这里

signal(SIGSEGV, sighandler);

您可能还应该使用 sigaction() 而不是 signal().请参阅相关手册页.

You should probably also use sigaction() instead of signal(). See relevant man pages.

在您的情况下,违规指令是试图取消引用 NULL 指针的指令.

In your case the offending instruction is the one which tries to dereference the NULL pointer.

printf("%d", *p);

接下来的内容完全取决于您的平台.

What follows is entirely dependent on your platform.

您可以使用 gdb 来确定触发信号的特定汇编指令.如果你的平台和我的一样,你会发现指令是

You can use gdb to establish what particular assembly instruction triggers the signal. If your platform is anything like mine, you'll find the instruction is

movl    (%rax), %esi

使用 rax 寄存器保存值 0,即 NULL.在您的信号处理程序中解决此问题的一种(不可移植!)方法是使用您的处理程序获得的第三个参数信号,即用户上下文.下面是一个例子:

with rax register holding value 0, i.e. NULL. One (non-portable!) way to fix this in your signal handler is to use the third argument signal your handler gets, i.e. the user context. Here is an example:

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

#define __USE_GNU
#include <ucontext.h>

int *p = NULL;
int n = 100;

void sighandler(int signo, siginfo_t *si, ucontext_t* context)
{
  printf("Handler executed for signal %d
", signo);
  context->uc_mcontext.gregs[REG_RAX] = &n;
}

int main(int argc,char ** argv)
{
  signal(SIGSEGV, sighandler);
  printf("%d
", *p); // ... movl (%rax), %esi ...
  return 0;
}

该程序显示:

Handler executed for signal 11
100

它首先通过尝试取消引用 NULL 地址来执行处理程序.然后处理程序通过将 rax 设置为变量 n 的地址来解决问题.一旦处理程序返回,系统会重试违规指令,这次成功.printf() 接收 100 作为它的第二个参数.

It first causes the handler to be executed by attempting to dereference a NULL address. Then the handler fixes the issue by setting rax to the address of variable n. Once the handler returns the system retries the offending instruction and this time succeeds. printf() receives 100 as its second argument.

不过,我强烈建议不要在您的程序中使用此类不可移植的解决方案.

I strongly recommend against using such non-portable solutions in your programs, though.

这篇关于为什么我不能忽略 SIGSEGV 信号?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆