这是我的代码,
#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 作为其第二个参数。
不过,我强烈建议不要在您的程序中使用此类不可移植的解决方案。
关于c - 为什么我不能忽略 SIGSEGV 信号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8456085/