我们最近在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;
}
然后他有一个简单的信号处理程序,只需打印信号编号。最终发生的事情是该程序将重复打印出它已收到一个数字为11的信号 - 一个SIGSEGV信号,并且不会退出循环。我们的教授发现这种行为很奇怪,并说他会调查它。
从我在互联网上进行的搜索看,行为似乎并不奇怪,因为程序在SIGSEGV的情况下处理收到的信号之后应该再次执行违规指令。但是,在任何官方UNIX或LINUX文档中,这种行为似乎都没有记录。您是否可以向我指出有关此类行为的文档的大致方向?
编辑:
信号处理程序是这样的:
void signal_handler(int signo)
{
printf("%d\n", signo);
}
将控制台输出重定向到生成的文件:
Iteration 0
11
11
11
11
11
... (only stopped if we sent it a SIGINT)
答案 0 :(得分:2)
正如您发现的文档所述,操作系统对从SIGSEGV返回的响应未定义。特别是对于这个例子,这意味着相关的图书馆标准没有定义它应该恢复的位置,而是留在它运行的机器的确切细节上。
从内存X86派生的机器将重新启动故障指令。但是,其他处理器跳过该指令继续下一步。一般来说,这两种方法都没有用,因为它们都会产生非常奇怪的行为。
正如您可能从中猜到的那样,通常取决于您正在运行的处理器。对于特定处理器,页面错误响应(以及其他故障)都是精确定义的,这包括如果您执行“返回”操作将会发生的情况。关于故障堆栈帧的指令。
通常,对于可移植程序,在SIGSEGV处理程序中唯一安全的做法是退出程序。但是,如果你非常非常小心地在库调用期间没有捕获信号或者类似的话,那么可能会使用setjmp / longjmp。