二进制边界的例外

时间:2012-05-28 16:06:05

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

我知道,这个问题已被问过很多次,但我无法找到解决问题的方法。

我有以下情况:

   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子句被调用。而是执行此代码的线程被中止。

我尝试了以下事项:

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

使用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使用自己的EException类型信息,而C使用A提供的类型信息吗?我该如何解决这个问题?

我的环境:

  • gcl 4.6.3 on x86_64-linux-gnu
  • 使用Qt

感谢您的帮助!

5 个答案:

答案 0 :(得分:3)

我和gcc有类似的问题&lt; 4.5使用跨共享库边界的RTTI符号,但不使用gcc 4.6。但是,您仍可能会发现以下信息非常有用。

如前所述,EException的vtable(包含typeinfo对象的一个​​条目)似乎在某些翻译单元中重复,这绝对是gcc&lt;的问题。 4.5(嗯,这是一个libsupc ++的问题,据我所知,没有合并type_info对象)。通过在EException中定义虚拟外联析构函数(它必须是标题中的第一个虚函数声明)来锚定A的vtable,这对我来说很有用。

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

答案 1 :(得分:1)

检查

  

-fvisibility =隐藏

链接器设置中的

选项。 如果设置,请将其更改为

  

-fvisibility =默认

答案 2 :(得分:1)

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

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

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

仅在extern定义上生成typeinfo。

答案 3 :(得分:0)

B正在使用它自己的EException类定义V typeinfo for EException,而C似乎使用未解析的(U意味着该类型在当前转换单元中未定义,必须由加载器和动态链接器解析)。 / p>

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

答案 4 :(得分:0)

您可以尝试使用A(在关联阶段)编译BC-rdynamic

GCC手册页讲述了-rdynamic:

  

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