我们最近在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)
正如您找到的文档所说,操作系统从 SIGSEGV 返回时的响应未定义。特别是对于这个例子,这意味着相关的库标准没有定义它应该在哪里恢复,而是将其留给正在运行的机器的确切细节。
X86 派生机器将从内存中重新启动出错的指令。然而,其他处理器会跳过该指令并继续执行下一条指令。一般来说,这两种方法都没有那么有用,因为它们都会产生非常奇怪的行为。
正如您可能从中猜测到的那样,具体执行的操作通常取决于您运行的处理器。对于特定的处理器,页面错误响应(和其他错误)都是精确定义的,这包括如果您在错误堆栈帧上执行“返回”指令将会发生什么。
一般来说,对于可移植程序,在 SIGSEGV 处理程序中唯一安全的做法是退出程序。但是,如果您非常非常小心地在库调用或类似过程中不捕获信号,则可以使用 setjmp/longjmp。
| 归档时间: |
|
| 查看次数: |
820 次 |
| 最近记录: |