欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

发生段错误后程序不崩溃

程序员文章站 2022-03-07 15:17:48
...

一个段错误的例子:

#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