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?