这是我的代码,
#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;
}
Run Code Online (Sandbox Code Playgroud)
在执行代码时,我遇到了分段错误.我使用SIG_IGN忽略了信号.所以我不应该得到分段错误.对?然后,printf()打印'*p'值后的语句也必须执行.对?
Ada*_*man 21
您的代码忽略了SIGSEGV而不是捕获它.回想一下,在处理完信号后重启了触发信号的指令.在你的情况下,处理信号没有改变任何东西,所以下次尝试违规指令时,它会以同样的方式失败.
如果你打算抓住信号改变这个
signal(SIGSEGV, SIG_IGN);
Run Code Online (Sandbox Code Playgroud)
对此
signal(SIGSEGV, sighandler);
Run Code Online (Sandbox Code Playgroud)
您可能也应该使用sigaction()而不是signal().请参阅相关手册页.
在您的情况下,违规指令是尝试取消引用NULL指针的指令.
printf("%d", *p);
Run Code Online (Sandbox Code Playgroud)
以下内容完全取决于您的平台.
您可以使用它gdb来确定特定汇编指令触发信号的内容.如果您的平台与我的平台一样,您会发现指令是
movl (%rax), %esi
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
该程序显示:
Handler executed for signal 11
100
Run Code Online (Sandbox Code Playgroud)
它首先通过尝试取消引用NULL地址来执行处理程序.然后处理程序通过将rax设置为变量的地址来修复问题n.一旦处理程序返回,系统就会重试违规指令,这次成功.printf()收到100作为其第二个参数.
不过,我强烈建议您不要在程序中使用此类非便携式解决方案.
cni*_*tar 14
您可以忽略该信号,但您必须对此进行一些操作.我相信你在发布的代码中所做的事情(忽略SIGSEGV通过SIG_IGN)根本不会起作用,原因在阅读粗体子弹后会变得明显.
当您执行某些操作导致内核向您发送SIGSEGV:
因此,如果你没有做任何事情,它就会不断循环.如果你不赶SIGSEGV你不退出,从而与正常流量的干扰,你必须:
小智 10
另一种选择是使用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;
}
Run Code Online (Sandbox Code Playgroud)
这里的setjmp/longjmp模式类似于try/catch块.但是它风险很大,如果风险函数超出堆栈,或者在释放之前分配资源但崩溃,则无法保存.最好检查你的指针,而不是间接通过坏指针.