【问题标题】:Behavior of c++ exceptions escaping into c programc++ 异常逃逸到 c 程序中的行为
【发布时间】:2017-06-23 07:49:25
【问题描述】:

假设我有一个用 c++ 实现但公开了纯 c 接口的共享库。然后在 c 程序中使用该库。

如果异常从 c++ 库逃逸到 c 应用程序中,gcc 是否对会发生什么做出任何保证?
会不会,例如总是终止程序?

我主要对 x64 和 ARMv7-R 上的 Linux 上的 gcc 的答案感兴趣,但也欢迎有关其他操作系统、编译器和体系结构的答案。

编辑:
明确一点:我不是在谈论让异常通过 c 函数,然后在调用 c++ 函数或与 c 或 c++ 回调交互时被捕获。应用程序代码本身是纯 c。在某些时候,它会调用共享库(内部是纯 c++)的一个函数,并且在该函数返回之前不会调用任何应用程序代码。还假设我无法控制用于编译应用程序代码的标志。

【问题讨论】:

  • 相信这样的异常将被视为未捕获的异常(即生成对std::terminate的调用),除非C代码使用-fexceptions编译,在在这种情况下异常可以传播(尽管最终可能仍然未被捕获)。但是,我没有可验证的来源。
  • 这就是为什么,如果混合 C 和 C++,一个共同的准则是 main() 被编译为 C++,而不是 C 并且 extern "C" 函数捕获异常并且不让它们传播给调用者。要么,要么 C++ 代码在没有异常支持的情况下编译,或者根本不抛出。通过 C 函数传播 C++ 异常是未定义的。
  • @Peter:是的,我对这种情况不满意,但事实就是这样。该库由 c 程序使用-我无法更改。如果我忘记在边界程序终止处捕获一些异常 - 通常 - 我可以接受(特别是,我通常不会尝试从 bad_alloc 中恢复),但我不想冒未定义行为的风险。所以我面临的问题是我是否应该将所有接口函数的实现包装到一个额外的try { ...} catch(...){ std::terminate(); } 块中以确保安全,或者我是否可以依赖编译器来产生相同的效果。
  • @Peter:由于 gcc afaik 定义了一些在 c++ 标准中未定义的东西,以便与 C 保持兼容,我希望这是其中之一。
  • @Peter:你有 "C++ 异常通过 C 函数的传播是未定义的" 的源代码(显然不能在c++标准)?如果是这样,我很乐意接受这个对我的问题的回答。

标签: c++ c exception gcc


【解决方案1】:

从我看到的关于 C++ 异常的情况来看,在我使用 from MSDNthis example 中,GCC 似乎在 catch 语句中包含以下程序集:

    call    __cxa_end_catch
    jmp     .L37
    movq    %rax, %rbx
    call    __cxa_end_catch
    movq    %rbx, %rax
    movq    %rax, %rdi
    call    _Unwind_Resume

它利用了我只能假设的 C++ 库调用处理异常的函数(例如_Unwind_resume)。因此,如果 C 代码链接到您的库,则必须提供这些符号/函数,这意味着代码将进入 C++ 库以处理异常。

但是,我还不知道 C++ 库需要什么才能完成其工作。我希望它是独立的,但我不确定。

编辑:这个问题的答案可能在于以下两个现有问题的答案(及其解释):

  1. How is the C++ exception handling runtime implemented?
  2. How are exceptions implemented under the hood?
  3. How do exceptions work (behind the scenes) in c++

编辑 2: 来自this answer,似乎因为__cxa_throw 使用表来跟踪可用的处理程序。我会假设当表格用尽时,在我们输入 C 代码时发生,该函数将调用std::terminate。因此,C++ 运行时(您必须已经链接)应该为您处理这个问题,而无需设置一个 catch all 子句。

由于我仍然不确定,我将编写一个对该理论的测试并用结果更新答案。

【讨论】:

  • 这方面有什么更新吗?我倾向于接受你的回答,但如果得到支持——如果不是官方文档——一些测试,会感觉更好。
【解决方案2】:

如果 C++ 异常从最外层的 try 块(只能在最外层的 C++ 函数调用内)逃逸,则无法捕获该异常。

根据 C++ 标准第 15.3/9 节,未捕获的异常总是会导致 std::terminate 终止。

【讨论】:

  • 编译器能否在编译共享库时假设任何通过“extern C”函数转义的异常都未被捕获?因为之后它“进入”了一个不受c++标准约束的c程序,所以我有点不愿意接受这个解释
  • @MikeMB 否,因为extern "C" 函数可能被 C++ 函数调用。 gcc(相对于 g++)甚至在 C 库中发出空的异常处理表,尽管我不知道它们是否或为什么它们是必要的。
  • 所以如果在主应用程序中没有生成异常相关的代码(因为它是一个C-Application)并且共享库里面的代码不知道异常是否会被缓存——运行时环境如何确定它是否应该终止应用程序?在谈论跨语言行为和共享库之类的东西都超出了 c++ 标准的范围时,一个纯粹基于 c++ 标准的答案是不够的。
猜你喜欢
  • 2015-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-20
相关资源
最近更新 更多