发生段错误后程序不崩溃
一个段错误的例子:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *tmp = NULL;
strcpy(tmp, "hello");
return 0;
}
执行结果
加上段错误处理函数:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
void sig_handle(int sig)
{
printf("sig_handle %d\n", sig);
}
int main()
{
char *tmp = NULL;
signal(SIGSEGV, sig_handle);
strcpy(tmp, "hello");
return 0;
}
执行结果:
程序陷入死循环打印, 是因为执行strcpy函数时会产生SIGSEGV信号,因为之前我们注册了SIGSEGV型号处理函数,所有会执行注册的sig_handle信号处理函数,处理完之后会返回到产生段错误的地方,然后接着会产生SIGSEGV信号。。。
正确的处理函数:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
void sig_handle(int sig)
{
printf("sig_handle %d\n", sig);
exit(0);
}
int main()
{
char *tmp = NULL;
signal(SIGSEGV, sig_handle);
strcpy(tmp, "hello");
return 0;
}
但是我们有时候不想让程序退出怎么办呢?那么就需要如下两个函数:
#include <setjmp.h>
int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int val);
int setjmp(jmp_buf env); 这个函数 将上下文 ,就是cpu和内存的信息保存到env中 (不用去理解 jmp_buf,就当我们平时用的buff好了),然后调用 void longjmp(jmp_buf env, int val); 的时候 跳转到使用env中的信息 ,恢复上下文 。如果是第一回调用setjmp 它会返回 0,如果是在 从longjmp 跳转过来的 ,那就返回 longjmp的参数 val,根据setjmp的返回值 我们就可以决定执行可能发生错误的代码还是直接跳过这段代码 。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <setjmp.h>
jmp_buf env;
void sig_handle(int sig)
{
printf("sig_handle %d\n", sig);
longjmp(env, 1);
}
int main()
{
char *tmp = NULL;
signal(SIGSEGV, sig_handle);
int ret = setjmp(env);
printf("ret = %d\n", ret);
if(ret == 0)
{
strcpy(tmp, "hello");
}
else
{
printf("after SIGSEGV\n");
}
return 0;
}
但是像下面这样使用还是有问题的
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <setjmp.h>
#include <unistd.h>
jmp_buf env;
void sig_handle(int sig)
{
printf("sig_handle %d\n", sig);
longjmp(env, 1);
}
int main()
{
char *tmp = NULL;
signal(SIGSEGV, sig_handle);
while(1)
{
int ret = setjmp(env);
printf("ret = %d\n", ret);
if(ret == 0)
{
strcpy(tmp, "hello");
}
else
{
printf("after SIGSEGV\n");
}
sleep(1);
}
return 0;
}
是因为程序产生SIGSEGV 信号进入到信号处理函数之后 这个信号会被 阻塞(block) 直到信号处理函数返回”,在进入到信号处理函数之后 ,这个时候 系统阻塞了 SIGSEGV 这个信号 ,当跳回到 int r = setjmp(env); 这行代码的时候 SIGSEGV 信号依然是阻塞的 ,那以后 再给他绑定信号处理函数 自然没有作用。
我们可以使用如下函数解决上述问题:
int sigsetjmp(sigjmp_buf env, int savesigs);
void siglongjmp(sigjmp_buf env, int val);
这两个函数和setjmp函数longjmp函数的唯一区别是sigsetjmp函数多了一个参数savesigs, 当 savesigs 不为 0时,会保存当前的信号屏蔽表 (signal mask),然后在使用siglongjmp 跳转的时候 会恢复 线程的 屏蔽表。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <setjmp.h>
#include <unistd.h>
jmp_buf env;
void sig_handle(int sig)
{
printf("sig_handle %d\n", sig);
siglongjmp(env, 1);
}
int main()
{
char *tmp = NULL;
signal(SIGSEGV, sig_handle);
while(1)
{
int ret = sigsetjmp(env, 1);
printf("ret = %d\n", ret);
if(ret == 0)
{
strcpy(tmp, "hello");
}
else
{
printf("after SIGSEGV\n");
}
sleep(1);
}
return 0;
}
上一篇: remove list
下一篇: 身份证验证js