注意: 很抱歉打破好事,但是你确实不想这样做。
捕获类似SIGINT, SIGTERM, SIGHUP
等[外部产生的]信号是完全有效的,以允许程序优雅地清理和终止可能有文件处于部分写入状态的程序。
但是,内部产生的信号,如SIGILL、SIGBUS、SIGSEGV
和SIGFPE
很难有意义地从中恢复。前三者都是纯粹的错误。而且,在我看来,SIGFPE
也是一个难处理的错误。
在此类信号之后,您的程序处于不安全和不确定的状态。即使捕获信号并使用longjmp/siglongjmp
也无法解决此问题。
而且,没有办法准确地知道损坏有多严重。或者,如果程序尝试继续运行,那么损坏会变得多么严重。
如果收到SIGFPE
,它是由浮点计算引起的[您可能可以解决]还是由整数除以零引起的?这个计算在哪里进行?您不知道。
尝试继续运行有时会导致10倍的损坏,因为现在程序已经失控。恢复后,程序可能没问题,但也可能有问题。因此,在事件之后,程序的可靠性无法确定。
是什么事件(即)导致了SIGFPE
的计算?也许,这不仅仅是一个单独的除法,而是导致值为零的一系列计算。这些值去哪了?这些现在可疑的值是否会被恢复操作后的代码使用?
例如,程序可能会覆盖错误的文件,因为失败的计算某种方式涉及选择调用者将要使用的文件描述符。
或者,您会泄漏内存。或者,破坏堆。或者,错误是否在堆分配代码本身中?
考虑以下函数:
void
myfunc(char *file)
{
int fd;
fd = open(file,O_WRONLY);
while (1) {
write(fd,buf,len);
x = y / z;
}
close(fd);
}
即使使用一个执行
siglongjmp
的信号处理器,
myfunc
写入的文件现在已经损坏/截断。而且,文件描述符不会被关闭。
或者,如果
myfunc
正在从文件中读取并将数据保存到某个数组中。那么该数组只被部分填充。现在,你会收到
SIGFPE
。这被信号处理器拦截,它执行了
siglongjmp
。
myfunc
的调用者之一通过执行
sigsetjmp
来“捕获”这个问题。但是,它能做什么呢?调用者不知道情况有多糟糕。它可能会假设
myfunc
读取的缓冲区已经完全形成,并将其写入另一个文件。那个文件现在已经损坏了。
更新:
哎呀,忘记提到 未定义行为 了...
通常,我们将 UB(例如越过数组末尾的写操作)与 segfault [SIGSEGV
] 相关联。但是,如果它导致 SIGFPE
呢?
这不再仅仅是“错误的计算”——我们在最早的检测点捕获[并忽略]了 UB。如果我们进行恢复,下一次使用可能会更糟。
这里有一个例子:
int x[10];
int y;
int z;
void
myfunc(void)
{
y = 23;
z = 37;
for (int i = 0; i <= 10; ++i)
x[i] = 0;
z /= y;
}
#include
语句,就可以编译成功。然而,编译器会输出关于变量设置但未使用等消息。 - user3629249