收到SIGSEGV信号后的处理行为?

Deu*_*ral 5 c unix linux

我们最近在UNIX中了解了OS类中的信号.我们使用C来访问unix API.

一个类伙伴在解除引用无效指针(到未分配的内存或空指针)然后处理生成的SIGSEGV信号时鬼混.他有一个代码块,它是这样的:

int* p;
int i = 0;
for (; i < 10; i++){
    printf("Iteration %d\n", i);
    p = i;
    int n = *p;
}
Run Code Online (Sandbox Code Playgroud)

然后他有一个简单的信号处理程序,只需打印信号编号.最终发生的事情是该程序将重复打印出它已收到一个数字为11的信号 - 一个SIGSEGV信号,并且不会退出循环.我们的教授发现这种行为很奇怪,并说他会调查一下.

从我在互联网上做的搜索来看,行为似乎并不奇怪,因为程序在SIGSEGV的情况下处理接收到的信号之后应该再次执行违规指令.但是,在任何官方UNIX或LINUX文档中,这种行为似乎都没有记录.您是否可以指出我关于此类行为的文档的一般方向?

编辑:

信号处理程序是这样的:

void signal_handler(int signo)
{
printf("%d\n", signo);
}
Run Code Online (Sandbox Code Playgroud)

将控制台输出重定向到生成的文件如下:

Iteration 0
11
11
11
11
11
... (only stopped if we sent it a SIGINT)
Run Code Online (Sandbox Code Playgroud)

use*_*044 2

正如您找到的文档所说,操作系统从 SIGSEGV 返回时的响应未定义。特别是对于这个例子,这意味着相关的库标准没有定义它应该在哪里恢复,而是将其留给正在运行的机器的确切细节。

X86 派生机器将从内存中重新启动出错的指令。然而,其他处理器会跳过该指令并继续执行下一条指令。一般来说,这两种方法都没有那么有用,因为它们都会产生非常奇怪的行为。

正如您可能从中猜测到的那样,具体执行的操作通常取决于您运行的处理器。对于特定的处理器,页面错误响应(和其他错误)都是精确定义的,这包括如果您在错误堆栈帧上执行“返回”指令将会发生什么。

一般来说,对于可移植程序,在 SIGSEGV 处理程序中唯一安全的做法是退出程序。但是,如果您非常非常小心地在库调用或类似过程中不捕获信号,则可以使用 setjmp/longjmp。