Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

typeinfo, shared libraries and dlopen() without RTLD_GLOBAL

I'm having some trouble with exceptions not functioning correctly (or at least, as I would hope; I know there are issues with this) across shared libraries when loaded using dlopen. I include some simplified example code here. The actual situation is myapp=Matlab, myext1=mexglx matlab extension, mylib is a shared library of my code between the two extensions (myext1, myext2)

mylib.h

struct Foo { Foo(int a); m_a; }
void throwFoo();

mylib.cpp

#include "mylib.h"
Foo::Foo(int a): m_a(a) {}
void throwFoo() { throw Foo(123); }

myext1.cpp

#include "mylib.h" 
#include <iostream>
extern "C" void entrypoint()    
{ 
   try { throwFoo(); } 
   catch (Foo &e) { std::cout << "Caught foo\n"; }
}

myext2.cpp Identical to myext1.cpp

myapp.cpp

#include <dlfcn.h>
int main()
{
  void *fh1 = dlopen("./myext1.so",RTLD_LAZY);
  void *fh2 = dlopen("./myext2.so",RTLD_LAZY);
  void *f1  = dlsym(fh1,"entrypoint");
  void *f2  = dlsym(fh2,"entrypoint");
  ((void (*)())func1)();  // call myext1 (A)
  ((void (*)())func2)();  // call myext2 (B)
}

Compiling this code:

g++ mylib.cpp -fPIC  -o libmylib.so -shared
g++ myext1.cpp -fPIC -o myext1.so -shared -L. -lmylib -Wl,-rpath=.
g++ myext2.cpp -fPIC -o myext2.so -shared -L. -lmylib -Wl,-rpath=. 
g++ myapp.cpp -fPIC -o myapp -ldl

The call to entrypoint() at A works as expected, with throwFoo() throwing the exception and entrypoint() catching it. The call at B however fails to catch the exception. Adding more diagnostic code shows that the typeinfo for the Foo class differs in the two extensions. Changing the order of the two dlopen calls makes no difference, the second loaded extension fails.

I know I can fix this by using RTLD_GLOBAL as an additional flag for dlopen, but the application (Matlab) using dlopen is out of my control. Is there anything I can do with mylib or myext1, myext2 to fix this problem?

I have to avoid using LD flags for runtime (since I cannot control the users running the Matlab binary). Any other suggestions?

like image 885
Brian O'Kennedy Avatar asked Feb 18 '11 18:02

Brian O'Kennedy


2 Answers

Rule 62 in "C++ Coding Standards" by Alexandrescu & Sutter:

"62. Don’t allow exceptions to propagate across module boundaries."

Although it can work when you do it carefully, for true portable and reusable code, this cannot be done. I would say it is a pretty common general rule when programming shared libraries or DLLs, do not propagate exceptions across module boundaries. Just use a C-style interface, return error codes, and do everything inside an exported function inside a try { } catch(...) { }; block. Also, the RTTI is not shared across modules, so don't expect Foo to have the same typeinfo in different modules.

like image 55
Mikael Persson Avatar answered Sep 20 '22 04:09

Mikael Persson


A simple work-around is to have your library dlopen itself with the RTLD_GLOBAL flag on the first use. This will override the previous open with RTLD_LOCAL and put everything in the global symbol namespace.

like image 25
R.. GitHub STOP HELPING ICE Avatar answered Sep 23 '22 04:09

R.. GitHub STOP HELPING ICE