【问题标题】:dynamic_cast failed when hiding symbol隐藏符号时dynamic_cast失败
【发布时间】:2011-07-04 05:35:06
【问题描述】:

我有很多静态库。一个是 static_lib_a.a。我创建了一个动态库 dynamic_lib.so 来将它们放在一起。

在 static_lib_a.a 中,它使用 xerces 3.1.1 来解析 xml。以下是static_lib_a.a

中的代码sn-p
xerces::DOMElement *pElementNode = dynamic_cast<xerces::DOMElement *>(pNode);

pNode 的类型是 xerces::DOMNode。它被分配给 xerces::DOMElement 的对象。这行代码将进行向下转换。

为了隐藏dynamic_lib.so中static_lib_a.a的所有符号,我使用-fvisibility=hidden来构建这个静态库。我发现如果我添加 -fvisibility=hidden,pElementNode 将在运行时返回一个 NULL 指针。

gcc 编译器的版本是 3.4.4。

以前有没有人遇到过类似的问题?

【问题讨论】:

  • 你的编译器太旧了。您是否尝试过使用较新版本的 gcc 编译代码?
  • 我不能这样做,因为其他旧模块是在 gcc 3.4.4 中构建的

标签: c++ linux gcc xerces gcc3


【解决方案1】:

gcc wiki 标题为“C++ 异常的问题”部分下描述了问题的根源。确保您点击那里的“模糊链接”链接并阅读有关虚拟表和类型信息的部分。

这一切都适用于您的情况,因为类 xerces::DOMNodexerces::DOMElement 不包含非纯非内联虚函数(实际上这些类完全包含在标题中)。这意味着任一类的虚拟表都会在包含其标头的每个目标文件中发出。

dynamic_cast 正常工作所需的任一类的类型信息符号在与虚拟表相同的对象中发出,即在包含其标题的每个对象文件中。

当您将库标记为隐藏可见性时,来自 static_lib_a.a 的对象中 xerces::DOMNodexerces::DOMElement 的所有类型信息符号都被标记为隐藏。正如 wiki 页面指出的那样,这可以确保链接器随后将其标记为隐藏在 dynamic_lib.so 中,并且您的 dynamic_cast 将失败。

【讨论】:

  • 太好了,你添加了缺失的部分。
【解决方案2】:

使用隐藏的可见性是确保您的图书馆仅通过指定的访问点使用的好方法。如果您修改它,这是一个巨大的优势,因为您确切地知道您的库是如何在外部使用的,因此您可能会破坏的限制。

这是一种与 Windows 非常相似的技术,它让您 declspec 什么是 DLL 的可访问部分的一部分,除了您没有说明是导入还是导出的细微差别,因此您的库可能使“可见” " 它使用而不是实现的函数。

不过,为了回答您的问题,我认为只有版本 4 以后才支持可见性。当然,我们在这里使用它

#if defined(__GNUC__) &amp;&amp; __GNUC__ &gt;= 4

当您使用隐藏可见性时,您需要明确说明您希望哪些符号可见。因此你有这个:

__attribute__((visibility("default")))

您可能会将其#define 变得更具可读性,例如 SO_EXPORT:

#define SO_EXPORT __attribute__((visibility("default")))

定义类:

class SO_EXPORT MyAccessInterface;

和类似的方法:

SO_EXPORT int doSomething( parameters );

我们实际上也有一个用于隐藏可见性的类似宏(如上,但使用“隐藏”而不是“默认”)。因此,即使我们对整个项目使用“默认”可见性,我们也可以隐藏一些实现细节。

#define SO_HIDDEN __attribute__((visibility("hidden")))

class SO_HIDDEN MyClassImpl;

【讨论】:

    【解决方案3】:

    dynamic_cast 要求派生类的 typeinfo 节点 指向基类的 typeinfo 节点,这是通过动态重定位完成的。如果 typeinfo 节点的符号不可见,则包含派生类节点的模块将拥有自己的副本,然后 dynamic_cast 假定这些类来自不同的树并且不允许转换。

    您需要在基类定义中添加一个声明默认可见性的属性。

    【讨论】:

    • xerces 是在没有“-fvisibility=hidden”的情况下构建的。每个调用者都应该看到每一类 xerces。
    • @Blanc Yang:这两个类都完全包含在标题中,因此 xerces 上的构建选项在这里无关紧要。详情请参阅我的回答。
    猜你喜欢
    • 2018-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-06
    • 1970-01-01
    相关资源
    最近更新 更多