为什么我不能忽略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()语句也必须执行。 对?

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

如果你打算赶上信号改变这一点

 signal(SIGSEGV, SIG_IGN); 

对此

 signal(SIGSEGV, sighandler); 

你可能也应该使用sigaction()而不是signal() 。 请参阅相关手册页。

在你的情况下,有问题的指令是试图解引用NULL指针的指令。

 printf("%d", *p); 

以下内容完全取决于您的平台。

你可以用gdb来建立什么特定的汇编指令触发信号。 如果你的平台和我的一样,你会发现这个指令是

 movl (%rax), %esi 

rax寄存器的值为0,即NULL 。 一个(不可移植的)方法来解决你的信号处理程序是使用你的处理程序得到的第三个参数信号,即用户上下文。 这里是一个例子:

 #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\n", signo); context->uc_mcontext.gregs[REG_RAX] = &n; } int main(int argc,char ** argv) { signal(SIGSEGV, sighandler); printf("%d\n", *p); // ... movl (%rax), %esi ... return 0; } 

这个程序显示:

 Handler executed for signal 11 100 

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

不过,我强烈建议不要在您的程序中使用这种非便携式解决方案。

你可以忽略这个信号,但你必须做一些事情。 我相信你在代码中所做的事情(忽略通过SIG_IGN SIGSEGV根本不会工作,原因在阅读大胆的项目符号后会变得明显。

当你做一些事情导致内核向你发送一个SIGSEGV:

  • 如果你没有一个信号处理程序,那么内核杀死这个进程就是这样
  • 如果你有一个信号处理程序
    • 你的处理程序被调用
    • 内核重新​​启动违规操作

所以如果你没有做任何事情,它会连续循环。 如果您确实遇到 SIGSEGV而您没有退出,从而干扰正常流程,您必须:

  • 修复这样的事情,有罪的操作不会重新启动或
  • 修复内存布局,以便在下一次运行时出现问题

另一种选择是用setjmp / longjmp括起危险的操作,即

 #include <setjmp.h> #include <signal.h> static jmp_buf jbuf; static void catch_segv() { longjmp(jbuf, 1); } int main() { int *p = NULL; signal(SIGSEGV, catch_segv); if (setjmp(jbuf) == 0) { printf("%d\n", *p); } else { printf("Ouch! I crashed!\n"); } return 0; } 

这里的setjmp / longjmp模式类似于try / catch模块。 但是如果你的风险函数溢出了堆栈,或者分配了资源但是在释放之前崩溃了,那么风险很大,而且不会救你。 最好是检查你的指针,而不是通过坏指针间接。

ANS:您将NULL指定给p指针

 char *p = NULL; 

然后你打印* p值:

 printf("%d",*p); 

这意味着您要打印位于空地址(即0地址位置)的值,这是不可能的。 这就是为什么它给分段错误。 在访问存储器的情况下会出现分段错误,这种情况现在对程序不可用。

尝试这个:

 char *p = (char*)malloc(sizeof(char)); *p = '\0'; printf("%d",*p); 

**注意:**这种类型的错误称为悬挂指针错误。 悬挂指针是错误/异常的情况下,语法是正确的,但用户尝试访问已指向NULL的指针的值。