【问题标题】:g++ problem: exception not caughtg ++问题:未捕获异常
【发布时间】:2009-09-22 08:22:43
【问题描述】:

情况是我有一个用 C++ 编写的动态库,它由另一个动态库为 Python 包装,也是用 C++ 编写的(具体由 SIP 生成)。第一个动态库定义了一个函数do_raise,它抛出了一个异常RaiserError,它是std::exception的一个子类。第二个动态库在包装do_raise 时尝试捕获RaiserError 以便将其转换为Python 异常。

使用 Visual C++ 构建,一切正常,RaiserError 被正确捕获。然而,在 Linux 上使用 g++,RaiserError 不会被捕获。如果我尝试捕获std::exceptionRaiserError 的基类),它会起作用。这里出了什么问题?这两个库是否有不同的 RaiserError 类型概念,因为它没有被 catch 块识别?

为了进行测试,我还在 C++ 库中编写了一个调用 do_raise 的小型可执行文件,在这里,即使使用 g++,我也能够捕获 RaiserError

【问题讨论】:

  • 提供您的编译器版本可能很有用。
  • 真实应用程序和您的测试应用程序之间必须存在差异。其中至少有一个是关键的。从您写的内容来看,我们很难说非常
  • 我使用一个版本的 g++,即 Ubuntu 9.04 附带的版本,即 4.3.3。与测试应用的不同之处在于它也是用 C++ 编写的,而不是 Python。自从我更改了 Python 包装器库的构建参数(与符号导出有关)以来,我已经能够使一个小型 Python 程序工作。但是,我的实际应用程序仍然无法运行,因此这表明问题归结为不兼容的构建参数。

标签: c++ exception exception-handling g++


【解决方案1】:

您无法跨模块边界可靠地传递 C++ 异常。在 Windows 上(至少对于 32 位进程)有一个标准的 ABI,但是使用 gcc,你就不走运了。

【讨论】:

  • 自 4.x 系列的所有版本以来,GCC 没有稳定的 ABI 吗?
【解决方案2】:

我相信 GCC 使用了某种指向类型信息的指针,如果它与指针不匹配,那么类型就不一样了。

这听起来像是 Microsoft C++ 回退到类型信息的字符串比较的情况之一(缓慢但有效)。这对 GCC 没有帮助。

您可以尝试确保异常类未隐藏并且类型信息在 ELF .so 文件中可见。尝试确保该类型仅在一个 .so 中定义。

编辑:我只是想到了这一点:我相信 ELF 动态链接器可以很好地处理 typeinfo 符号的多个副本,并且会选择一个副本来使用。我认为如果您链接一些静态代码或在 .so 或可执行文件之一中执行 -Bsymbolic,您可以获得多个副本。

【讨论】:

  • 您知道相关符号在 ELF 库中的外观吗?作为一个例子,我在我的真实项目中有一个异常“LoadImageError”。在定义/抛出库中,我有这些 typeinfo 符号: 000b9634 V typeinfo for igmUtil::LoadImageError 000a3d5c V typeinfo name for igmUtil::LoadImageError 在 Python 包装库中(试图捕获异常): 000174b8 d DW.ref._ZTIN7igmUtil14LoadImageErrorE 00016540 igmUtil::LoadImageError 的 V 类型信息 00011e85 igmUtil::LoadImageError 的 V 类型信息名称
  • 嗯 .. 显然粘贴符号表摘录不是一个好主意 :) 我猜我的菜鸟表明。我创建了一个 pastebin 页面:pastebin.com/f52cf15b1
【解决方案3】:

我以前没有遇到过捕获 .so 引发的异常的问题,因此无法与我在这里看到的其他响应交谈。

与查找无关的是你的任何析构函数是否可能抛出异常:如果你在解构函数中抛出一个新异常,同时展开堆栈并抛出第一个异常,你的程序将中止,与任何包装 try/catch 无关.使用 g++,错误消息看起来就像您没有捕获第一个异常一样。小心地逐步展开堆栈,看看这是否会发生在您身上。

【讨论】:

    【解决方案4】:

    根据其他答案,问题是(更有可能)在 .so 中缺少 RTTI 信息。

    尝试将 -Wl,-E 附加到您的编译器标志,这将导致链接器导出所需的类型信息。

    VC++ 使用字符串比较(相对于指针比较)来匹配类型(同时使用动态转换、捕获等),这在运行时速度较慢,但​​会导致 dll 更小(因为 dll 中导出的 RTTI 更少)。

    这将是可靠的,只要您使用相同的编译器来编译您的共享对象(或者您使用与供应商无关的 ABI,如 g++ >= 4.3 可用)。

    【讨论】:

    • 感谢有关 -Wl,-E 的提示,但它对我没有多大帮助:/
    猜你喜欢
    • 2018-02-04
    • 2011-03-16
    • 2013-03-14
    • 1970-01-01
    • 1970-01-01
    • 2010-09-28
    • 2012-05-31
    相关资源
    最近更新 更多