Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dynamic_cast fails when used with dlopen/dlsym

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
like image 886
Kees-Jan Avatar asked Feb 28 '10 17:02

Kees-Jan


2 Answers

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
like image 83
Kees-Jan Avatar answered Oct 07 '22 01:10

Kees-Jan


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.

like image 40
bmargulies Avatar answered Oct 07 '22 00:10

bmargulies