【问题标题】:Handling CPU exceptions in C++在 C++ 中处理 CPU 异常
【发布时间】:2011-06-15 06:36:10
【问题描述】:

是否有跨平台的方法来处理 CPU 异常,如分段错误或除以零?可以说,我需要调用一些可能不安全的函数(例如从插件文件中),这可能会导致段错误或其他一些我在执行之前无法测试的问题。我知道,C标准库有信号处理函数,但我不知道如何使用它们来处理问题以避免程序终止(我想,我不能只是跳转到有问题的函数执行之前的位置,或者我可以吗?)。 在 windows 下我可以使用 SEH 异常处理程序,但在 Linux 或任何其他操作系统下我不能这样做。使用我自己的异常处理程序来处理这些问题怎么样,Windows/Linux 之间有多大不同?这甚至可能吗(通过汇编程序——让我们说只是在 x86 平台上)?

我主要是出于好奇而询问,我并没有试图解决现有的问题(目前)。 谢谢

【问题讨论】:

  • 虽然在发生段错误的情况下您无法真正做任何事情,但我必须承认除以零、上溢和下溢的情况总是让我觉得很奇怪,能够抓住它们会很棒。

标签: c++ exception cpu signals


【解决方案1】:

问题是如果插件段出错,你不能保证你的主程序将处于什么状态。即使您可以捕获 SIGSEGV(我相信您可以),您的应用程序也没有恢复的好方法。

您需要做的是在forked 进程中运行插件,这样如果它崩溃,您的主程序也不会被删除。例如,您可以使用管道在进程之间进行通信。

【讨论】:

  • 该插件的示例只是一个可以使用它的想法。这样的插件必须按照您的建议作为子进程运行,或者它必须遵循一组严格的规则,因为它可能会或可能不会这样做(但同样,我无法强制执行这)。但是,如果我只需要读/写一些内存,我应该能够在段错误的情况下恢复。
【解决方案2】:

不,没有标准方法。在 C++ 中,这种“CPU 异常”是未定义行为的表现,即 C++ 标准没有指定任何关于它们的行为或之后发生的任何事情。甚至标准 C++ 中也不存在“段错误”的概念。取消对 NULL 指针的引用可能会使您的计算机着火,显然此时几乎没有什么可以捕捉的了。

C 也没有解决这个问题:SIGSEGV 不是标准的 C 信号;这是一个 POSIX 扩展。例如,Windows 没有 SIGSEGV。

【讨论】:

    【解决方案3】:

    libsigsegv 是一个用于处理分段错误和堆栈溢出的跨平台库。但是,在绝大多数情况下,当您检测到分段错误时,正确的做法是尽快终止执行,而不是尝试从中恢复。段错误通常表示存在错误或内存损坏,一旦内存损坏,几乎不可能从中恢复。

    【讨论】:

    • 是的,这样的解决方案只适用于少数情况,我可以保证程序的环境没有被破坏。
    • @John Holecek 你们如何在任何情况下提供这样的保证?
    • 例如测试一个指针值是否指向一个有效的内存位置——这样的事情可能对某种垃圾收集器有用。
    • @John Holecek:不,测试指针是否有效实际上可能导致比它修复的错误更多。有关原因的详细讨论,请参阅blogs.msdn.com/b/oldnewthing/archive/2006/09/27/773741.aspx
    • 是的,你可能是对的。这种方法充其量是错误的:-/但这实际上是我提出这个问题的原因之一 - 学习一些新的东西,看看它是否可行。
    【解决方案4】:

    这在标准 C++ 中没有涉及,但是常见的桌面操作系统提供了执行此操作的工具。 Windows 具有结构化异常处理 (SEH),相关编译器扩展可用,而 POSIX 提供信号处理。

    通常情况下,我会说您不应该捕获 CPU 异常 - 它们只会在您的程序出现错误时发生,并且此时需要破解调试器,而不是继续。

    您不能使用相同的方法 - 即使在汇编程序中也是如此。这些功能由操作系统提供——当 CPU 引发异常时,它会转到操作系统来决定如何处理它,而不是用户模式。不仅如此,我还要说 SEH 和信号处理很容易不同,足以保证在代码中使用它们时采用根本不同的方法,所以简单的 #ifdef 不会解决问题。

    setjmplongjmp 只能用于用户模式代码产生的“信号”,而不是操作系统级别。

    【讨论】:

      【解决方案5】:

      我认为不存在真正的跨平台解决方案。

      在 windows 下可以使用_set_se_translator 将 SEH 异常转换为 C++ 异常。

      如何在Linux下做同样的事情,请参阅下面的文章C++ exception-handling tricks for Linux

      【讨论】:

        【解决方案6】:

        信号处理程序可以修复程序执行到某个点; signal(7) 手册页中记录了具体允许的内容。

        有一些实现会

        • 从 SIGSEGV 处理程序返回错误指令(这允许您更改内存映射并返回),并且

        • 转到 SIGFPE 故障后的指令(因此您的信号处理程序需要查找指令并提供结果)

        请注意,这充其量是实现定义的。该手册告诉您不要依赖任何这些。你被警告了。 :)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-06-11
          • 2011-04-27
          • 2011-09-11
          • 1970-01-01
          相关资源
          最近更新 更多