I have a dynamic cast which is failing. The class layout is like this:
class A1
{
public:
virtual int foo1()=0;
};
class A2
{
public:
virtual int foo2();
};
class A3
{
public:
virtual int foo3();
};
class B : public A1, public A2, public A3
{
int bar();
};
Now I use pointers ( so no slicing can occur ) for the downcast.
main()
{
B b;
A1* a1 = dynamic_cast<A1*> (&b); // ok
B* b1 = dynamic_cast<B*> (a1); // ok
A2* a2_1 = dynamic_cast<A2*> (a1); // OSX 10.7 ok, OSX 10.9 fail
A2* a1_2 = dynamic_cast<A2*> (b1); // ok
};
The downcast works, the upcast works but the sidecast does not work always. Under OSX 10.7 the sidecast works, under OSX 10.9 it does not ( GCC 4.2 using dynamic c++ stdlib). Looking at the vtable using gdb I can clearly see A2 methods and members listed.
My questions:
a) Is the sidecast technically correct? Should it work or is this a runtime bug?
b) If the sidecast depends on the runtime, where is this runtime defined? I always thought this is a part of the binary?
c) How does a failing dynamic_cast look like (when looking at assembly), and how can you track down such problems?
Update: this is what i see in the system console
11/01/15 14:16:27,435 APPNAMECHANGED[15280]: dynamic_cast error 1: Both of the following type_info's should have public visibility. At least one of them is hidden. 10A1, 15A2.
So c) is answered, at least for OSX 10.9. Have a look at the console. (Linux, someone?) It looks like a problem about symbol visibility. Doc says (gcc.gnu.org/wiki/Visibility)
However, this isn't the full story - it gets harder. Symbol visibility is "default" by default but if the linker encounters just one definition with it hidden - just one - that typeinfo symbol becomes permanently hidden (remember the C++ standard's ODR - one definition rule). This is true for all symbols, but is more likely to affect you with typeinfos; typeinfo symbols for classes without a vtable are defined on demand within each object file that uses the class for EH and are defined weakly so the definitions get merged at link time into one copy.
This leads to the next question,
d) how can we track down which symbol get at least once marked hidden, and where and why? Is there a tool to inspect .o files?
The issue was finally resolved after we found that the executable linked against a dylib which was itself linked statically against the c++ runtime but was compiled with a different compiler (gcc 4.8 vs clang).