21

我知道,这个问题已经被问过很多次了,但是我找不到我的问题的解决方案。

我有以下情况:

   A
  / \
 /   \
B <-- C
  • A 是一个包含类的共享库EException
  • B 和 C 链接 A
  • C也是一个共享库
  • B 在运行时动态加载 C

在某些时候 C 抛出一个实例EException

void doSometing() {
    throw EException("test-message");
}

B我想捕捉这个异常:

try {
    doSomething();
} catch (const EException& ex) {
    // Not reached
} catch (...) {
    // Not reached
}

但正如代码中所提到的,没有一个 catch 子句被调用。相反,执行此代码的线程被中止。

我尝试了以下事情:

  • 的可见性属性EException在编译 A 时设置为“默认”
  • EException文件只包含声明
  • -fvisibility=hidden在 A、B 和 C 中使用链接器选项
  • -E在 C 中使用链接器选项

使用nm我得到A

0000000000066260 T EException::EException(QString const&)
0000000000066306 T EException::EException(EException const&)
00000000000661d0 T EException::EException() 
0000000000066260 T EException::EException(QString const&) 
0000000000066306 T EException::EException(EException const&) 
00000000000661d0 T EException::EException() 
00000000000664de T EException::~EException()
000000000006641e T EException::~EException() 
000000000006641e T EException::~EException() 
00000000000663b6 T EException::operator=(EException const&)
<...>
000000000028de40 V typeinfo for EException
000000000028dd80 V typeinfo for EException*
000000000007342b V typeinfo name for EException
0000000000072ab7 V typeinfo name for EException*
000000000028de00 V vtable for EException

对于B

U EException::EException(QString const&)
U EException::~EException()
<...>
0000000000726f60 V typeinfo for EException

C

U EException::EException(QString const&)
U EException::~EException()
<...>
U typeinfo for EException

问题可能是,它B使用自己的 typeinfo EException,而C使用 提供的A?我将如何解决这个问题?

我的环境:

  • x86_64-linux-gnu 上的 gcc 4.6.3
  • 使用 Qt

谢谢您的帮助!

4

5 回答 5

3

我在 gcc < 4.5 和跨共享库边界使用 RTTI 符号时遇到了类似的问题,但在 gcc 4.6 中没有。但是,您可能仍会发现以下信息很有用。

如前所述,vtable(包含 typeinfo 对象的条目)EException似乎在某些翻译单元中重复,这绝对是 gcc < 4.5 的问题(好吧,据我所知,这是 libsupc++ 的问题,不是合并 type_info 对象)。EException通过定义一个虚拟的外联析构函数(它必须是头文件中的第一个虚函数声明)来锚定 vtableA对我来说是诀窍。

发布完整的头文件EException也可能会有所帮助。

于 2012-06-09T16:01:04.497 回答
1

检查

-fvisibility=隐藏

链接器设置中的选项。如果已设置,请将其更改为

-fvisibility=默认

于 2012-07-14T09:31:09.630 回答
1

恕我直言,这与编译器标志无关。

将您的异常对象声明为 extern,并且除了在您的主二进制文件中之外,不要在任何地方提供任何实现。

这将强制链接器(动态链接器 BTW)使用唯一可能的实现。

仅在外部定义上不生成类型信息。

于 2012-08-01T09:55:23.590 回答
0

您可以尝试编译ABC使用-rdynamic(在链接阶段)

GCC 手册页讲述了 -rdynamic:

在支持它的目标上将标志 -export-dynamic 传递给 ELF 链接器。这指示链接器将所有符号(不仅是使用的符号)添加到动态符号表中。对于“ dlopen ”的某些用途或允许从程序中获取回溯,需要此选项。

于 2012-06-15T18:19:20.857 回答
0

B 使用它自己的 EException 类定义V typeinfo for EException,而 C 似乎使用 Unresolved 类定义(U 表示该类型在当前翻译单元中未定义,必须由加载器和动态链接器解析)。

验证 B 仍然是一个共享库,并且它不是静态链接到 A 而是动态链接,防止 C 找到 A 的东西,因为我看不到 B 不会链接与 A 相同的类型。照顾你的标题 ^^。

于 2012-05-29T01:57:00.573 回答