dynamic_cast failed when hiding symbol

南笙酒味 提交于 2020-01-02 08:25:43

问题


I have many static libraries. One is static_lib_a.a. I create a dynamic library, dynamic_lib.so to put them together.

In static_lib_a.a, it uses xerces 3.1.1 to parse xml. The following is the code snippet in static_lib_a.a

xerces::DOMElement *pElementNode = dynamic_cast<xerces::DOMElement *>(pNode);

The type of pNode is xerces::DOMNode. It is assigned to an object of xerces::DOMElement. This line of code will do downcasting.

In order to hide all symbols of static_lib_a.a in dynamic_lib.so, I use -fvisibility=hidden to build this static library. I found if I add -fvisibility=hidden, pElementNode will return a NULL pointer in runtime.

Version of gcc compiler is 3.4.4.

Does anyone have similar issues before?


回答1:


The root of your problem is described on the gcc wiki under the section entitled "Problems with C++ exceptions". Make sure you follow the "vague linkage" link there and read the sections on virtual tables and typeinfo.

This all applies to your case because the classes xerces::DOMNode and xerces::DOMElement contain no non-pure, non-inline virtual functions (in fact these classes are contained entirely in headers). This means that the virtual table for either class is emitted in every object file that includes its header.

The typeinfo symbols for either class, which are required for dynamic_cast to work properly, are emitted in the same object as the virtual table i.e. in every object file that includes its header.

When you marked your library with hidden visibility all the typeinfo symbols for xerces::DOMNode and xerces::DOMElement in objects from static_lib_a.a were marked hidden. As the wiki page points out, this ensures that the linker will then mark it as hidden in dynamic_lib.so and your dynamic_cast will fail.




回答2:


Using hidden visibility is a great way to ensure your library is only being used through specified access points. This is a huge advantage if you ever modify it, as you know exactly how your library is being used externally and therefore the limitation of what you might potentially break.

It is a very similar technique to Windows making you declspec what is part of the accessible part of a DLL, except the slight difference that you do not state if you are importing or exporting, and your library may therefore be making "visible" functions it uses rather than implements.

To answer your question though, I think visibility is only supported version 4 onward. Certainly we use it here with this

#if defined(__GNUC__) && __GNUC__ >= 4

When you use hidden visibility, you need to explicity state which symbols you do wish to be visible. Thus you have this:

__attribute__((visibility("default")))

which you will probably #define to be something more readable, maybe SO_EXPORT thus:

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

The define classes:

class SO_EXPORT MyAccessInterface;

and methods something like:

SO_EXPORT int doSomething( parameters );

We actually also have a similar macros for hidden visibility (as above but with "hidden" instead of "default"). Thus even when we use "default" visibility for the whole project we can hide some implementation detail.

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

class SO_HIDDEN MyClassImpl;




回答3:


dynamic_cast requires the typeinfo node for the derived class to point at the typeinfo node for the base class, which is done with a dynamic relocation. If the symbol for the typeinfo node is not visible, then the module containing the node for the derived class will have its own copy, and dynamic_cast then assumes that these classes are from distinct trees and disallows the cast.

You need to add an attribute declaring default visibility to the base class definition.



来源:https://stackoverflow.com/questions/5116333/dynamic-cast-failed-when-hiding-symbol

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!