typeinfo, shared libraries and dlopen() without RTLD_GLOBAL

随声附和 提交于 2020-01-31 03:34:45

问题


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?


回答1:


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.




回答2:


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.




回答3:


Is there anything I can do with mylib or myext1, myext2 to fix this problem?

As an alternative to using RTLD_GLOBAL you can simply use the enviroment variable LD_PRELOAD when you run your application in order to fix your problem. You don't have to recompile anything:

LD_PRELOAD=libmylib.so ./myapp


来源:https://stackoverflow.com/questions/5044993/typeinfo-shared-libraries-and-dlopen-without-rtld-global

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!