In one ouf our framework i have a code like this:
XMLParser.dylib:
DOMElement.hpp:
class DLLEXPORT DOMElement : DOMNode
{
…
virtual ~ DOMElement() {};
…
}
In the application we have code like:
XMLTest.cpp:
#include “DOMElement.hpp”
…
if(node->getNodeType()== DOMNode::ELEMENT_NODE )DOMElement* element = dynamic_cast(node);
The DLLEXPORT expands to __attrbiute((visibility(“default”)) in XMLParser.framework
The DLLEXPORT expands to __attrbiute((visibility(“hidden”)) in XMLTest
The issue is that the dynamic_cast fails by returning 0.
I see the followings:
- the DOMElement class has two type_info entries:
- one inside the XMLParser.dylib with default visibility
- one inside the XMLTest application with hidden visibiliy
- the linker looks for the type_info entry of DOMElement: __ZTIN10DOMElementE
It sees a __ZTIN10DOMElementE entry marked with hidden in XMLTest.cpp.o, it also sees a the same entry marked as default in XMLParser.dyld - From runtime it seems that the linker selects the hidden one. And this causes issue with dynamic_cast, as there’s two entries with the same symbol.
Questions:
- It seems that linker prefers the hidden symbol the same DSO to the visible in the different DSO?! Is this a rule?!
It seems to make sense: You have a DSO with NewWindow, then you have an internal function called NewWindow (“hidden”). If the linker should choose, it should prefer the “hidden” one to the one in different framework.
- If so wouldn’t it be logical to have an “imported” visibility, where the visible symbol in the different DSO would be preferred over the “imported” symbol in the same DSO.
- Setting the type_info visible in both modules seems to solve the problem. Why? What happens if the linker sees 2 visible entries, one in the actual module the other in a different DSO?!
References: