【问题标题】:C++: Is using segvcatch safe?C++:使用 segvcatch 安全吗?
【发布时间】:2012-09-13 16:43:42
【问题描述】:

我偶然发现了segvcatch 库,它承诺将段错误和浮点错误包装到适当的异常中。

使用这个库是安全的,如果我添加所有捕获的段错误将仅是空指针访问的前提条件(即,没有数组溢出或无效指针可能在段错误之前完全搞砸内存,无论如何都会导致未定义的行为) ?捕获 nullptr 段错误后,程序是否仍具有定义的语义?浮点错误呢?他们表现得更好/不同吗?

旁注:请不要让 cmets 声明任何产生段错误的程序都是格式错误的,应该调试/修复。我知道,我同意。不过,我对这个问题很感兴趣。

【问题讨论】:

  • 这个 segvcatch 是个奇怪的东西。它有效吗?是否需要任何费用(性能方面)?
  • @Walter:好吧,至少它附带的测试用例似乎可以在 linux 下运行。

标签: c++ exception-handling segmentation-fault signals


【解决方案1】:

不安全。

信号处理程序非常简单,但它们完全是错误的。这是 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 或重新启动机器。

【讨论】:

  • 好的,但它在 gcc 中有效,尤其是在使用 -fnon-call-exceptions 时。虽然方式有点不同:stackoverflow.com/questions/5860999/…
  • 大卫,为什么这是一个非常非常糟糕的主意?为什么它在 C++11 中是非法的? @queen3 使用-fnon-call-exceptions 有什么意义?
  • 感谢沃尔特,好评!此外,图书馆似乎在段错误周围做了一些魔法,比如调整 PC 和其他东西。所以你发布的处理程序不是库的唯一贡献(单行信号处理程序不需要自己的库......)
  • @Walter:很多原因。 #1:如果 SIGSEGV 是由粉碎堆栈导致的,则没有堆栈可展开。 #2:关于 RAII 不安全,因为在处理程序的上下文中调用 free()(以及因此 delete)是不安全的。 #3:有一大堆函数不能安全调用,并且在throw 之后发生的所有事情都在信号处理程序的上下文中完成。 #4:在信号内部产生的信号是很成问题的。例如,在我的计算机上,信号更改为 SIGSTOP。我什至没有得到核心转储。我得到了一个冻结的可执行文件,我必须杀死 -9。
  • @DavidHammen:浮点信号比如被零除呢?在这样的信号之后,堆栈和其他东西不应该被破坏。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-10
  • 2022-11-16
  • 1970-01-01
  • 2012-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多