隐藏符号时dynamic_cast失败

时间:2011-02-25 10:52:19

标签: c++ linux gcc xerces gcc3

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

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

中的代码段
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。

之前有没有人有过类似的问题?

3 个答案:

答案 0 :(得分:3)

问题的根源在gcc wiki下标题为“C ++异常问题”的部分中进行了描述。确保按照那里的“模糊链接”链接阅读有关虚拟表和typeinfo的部分。

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

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

当您使用隐藏的可见性标记库时,static_lib_a.a中对象中xerces::DOMNodexerces::DOMElement的所有typeinfo符号都标记为隐藏。正如维基页面指出的那样,这可以确保链接器将其标记为在dynamic_lib.so中隐藏,并且您的dynamic_cast将失败。

答案 1 :(得分:1)

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

这是一种非常类似于Windows的技术,使你可以将declspec作为DLL的可访问部分的一部分,除非您导入或导出时没有说明的细微差别,因此您的库可能因此“可见” “它使用的功能而不是实现。

为了回答你的问题,我认为只有第四版支持可见性。当然我们在这里使用它

#if defined(__GNUC__) && __GNUC__ >= 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;

答案 2 :(得分:0)

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

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