views:

417

answers:

3

Intro

Let me apologise upfront for the long question. It is as short as I could make it, which is, unfortunately, not very short.

Setup

I have defined two interfaces, A and B:

class A // An interface
{
public:
  virtual ~A() {}

  virtual void whatever_A()=0;
};

class B // Another interface
{
public:
  virtual ~B() {}

  virtual void whatever_B()=0;
};

Then, I have a shared library "testc" constructing objects of class C, implementing both A and B, and then passing out pointers to their A-interface:

class C: public A, public B
{
public:
  C();
  ~C();

  virtual void whatever_A();
  virtual void whatever_B();
};

A* create()
{
  return new C();
}

Finally, I have a second shared library "testd", which takes a A* as input, and tries to cast it to a B*, using dynamic_cast

void process(A* a)
{
  B* b = dynamic_cast<B*>(a);
  if(b)
    b->whatever_B();
  else
    printf("Failed!\n");
}

Finally, I have main application, passing A*'s between the libraries:

A* a = create();
process(a);

Question

If I build my main application, linking against the 'testc' and 'testd' libraries, everything works as expected. If, however, I modify the main application to not link against 'testc' and 'testd', but instead load them at runtime using dlopen/dlsym, then the dynamic_cast fails.

I do not understand why. Any clues?

Additional information

  • Tested with gcc 4.4.1, libc6 2.10.1 (Ubuntu 9.10)
  • Example code available
+2  A: 

In general, gcc does not support RTTI across dlopen boundaries. I have personal experience with this messing up try/catch, but your problem looks like more of the same. Sadly, I'm afraid that you need to stick to simple stuff across dlopen.

bmargulies
I haven't tried, but I guess following the instructions at http://gcc.gnu.org/faq.html#dso should fix your problem as well.
Kees-Jan
+3  A: 

I found the answer to my question here. As I understand it, I need to make the typeinfo available in 'testc' available to the library 'testd'. To do this when using dlopen(), two extra things need to be done:

  • When linking the library, pass the linker the -E option, to make sure it exports all symbols to the executable, not just the ones that are unresolved in it (because there are none)
  • When loading the library with dlopen(), add the RTLD_GLOBAL option, to make sure symbols exported by testc are also available to testd
Kees-Jan
I'll be interested to hear if this actually works.
bmargulies
It does. If you like to see for yourself, follow the "example code" link in the question, and make the modifications above.
Kees-Jan
+2  A: 

I have to add to this question since I encountered this problem as well.

Even when providing -Wl,-E and using RTLD_GLOBAL, the dynamic_casts still failed. However, passing -Wl,-E in the actual application's linkage as well and not only in the library seem to have fixed it.

Fredrik Ullner
I had to do that too. Actually in my case the library didn't need -Wl,-E, just the main app.
Nathan Monteleone