我刚刚偶然发现了segvcatch库,它承诺将段错误和浮点错误包装到适当的异常中。
使用这个库是否安全,如果我添加所有捕获的段错误将仅是空指针访问的前提条件(即,没有数组溢出或无效指针可能在段错误之前完全搞砸内存,无论如何都会导致未定义的行为)?捕获 nullptr 段错误后,程序是否仍具有定义的语义?浮点错误呢?他们表现得更好/不同吗?
旁注:请不要发表评论,说明任何产生段错误的程序都是格式错误的,应该调试/修复。我知道,我同意。不过,我对这个问题很感兴趣。
我刚刚偶然发现了segvcatch库,它承诺将段错误和浮点错误包装到适当的异常中。
使用这个库是否安全,如果我添加所有捕获的段错误将仅是空指针访问的前提条件(即,没有数组溢出或无效指针可能在段错误之前完全搞砸内存,无论如何都会导致未定义的行为)?捕获 nullptr 段错误后,程序是否仍具有定义的语义?浮点错误呢?他们表现得更好/不同吗?
旁注:请不要发表评论,说明任何产生段错误的程序都是格式错误的,应该调试/修复。我知道,我同意。不过,我对这个问题很感兴趣。
不安全。
信号处理程序非常简单,而且它们完全是错误的。这是 SEGV 处理程序:
void default_segv()
{
throw std::runtime_error("Segmentation fault");
}
这是相当非法的,至少在 POSIX 上是这样。从信号处理程序中抛出异常是一个非常非常糟糕的主意。
附录
那么为什么这是一个坏主意呢?
使用 SIGALRM,这比一个坏主意更糟糕;这是未定义的行为,因为警报是异步的。使用 SIGSEGV 和 SIGBUS 这是一个非常糟糕的主意。对于其他信号,这只是一个坏主意。有时它可能会起作用。其他时候,可能不会。当魔法不起作用时,结果可能是非常灾难性的。
我先看看SEGV。分段违规和总线错误的一个常见原因是破坏堆栈。如果这是信号的原因,则没有可展开的堆栈。将throw
尝试展开堆栈,这将引发另一个 SEGV。怎么办?在我的电脑上,这是一场灾难。
无论信号如何,在信号处理程序中抛出对于 RAII 而言都是不安全的,因为free()
(因此delete
)在处理程序的上下文中调用是不安全的。从信号处理程序的上下文中调用大量的函数是不安全的。在处理程序中发生的所有事情都是throw
在信号处理程序的上下文中完成的,因为throw
不会从处理程序返回。throw
绕过返回。
那些不安全的调用和不安全的展开意味着可以在处理旧信号的同时发出新信号。这个递归信号是很成问题的。例如,在我的计算机上,信号变为 SIGSTOP。该程序不会退出,它不会丢弃核心。它只是挂在那里,永久冻结,直到我杀死 -9 或重新启动机器。