This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: RE: exceptions not caught from shared libraries loaded with dlopen


On Fri, 2007-10-19 at 15:05 +0200, tahoma@gmx.de wrote:
> > Adding RTLD_GLOBAL to dlopen flags solves the problem for now. I have to
> > investigate further. I stumbled across this behaviour while creating C++
> > Wrappers for Python with Swig. The order of importing the generated wrapper
> > libraries results in different result. Exceptions thrown in C++ will be
> > caught one time the other time not. So I stripped down the generated wrapper
> > code and tried to emulate Python's import. I do not know whether Python uses
> > RTLD_GLOBAL when importing libraries or not.
> 
> Sorry for bothering you with this problem.
>  The RTLD_GLOBAL hint was very helpful and helped me to 
> solve this problem with my wrappers. One has to set this 
> flag for Python as well because it uses RTLD_LOCAL as default.
> 
> Thanks for pointing me into the right direction,

I think this is a 'bug' in the code: you should NOT use RTLD_GLOBAL.
The correct flags are RTLD_NOW | RTLD_LOCAL.

What you MUST do is make sure all the methods of exception
E are declared but not defined in the header file,
including copy constructor and assignment operator even if they're
private and not to be used. In other words, make sure the compiler
does NOT generate any methods, and make sure no method implementations
are inline or otherwise visible. This should ensure the rtti/vtables
go in the library X you want (this isn't guaranteed, but most
compilers lay down vtables/rtti with side the first method,
constructor, or destructor defined, possibly in several object
files, but never if only the class definition is seen ..
otherwise dynamic linkage would create duplicate vtables/rttis.
Duplicate rtti causes the problem you have encountered).

If you dlopen(), you should NOT allow any symbols to leak into
the symbol table! And you should NOT allow any undefined symbols
in the library to be bound against the global symbol table either,
just because they happen to be there.

The plugin library must be linked against the libraries that contain
the definitions of symbols it requires, and so must every other
library AND the application (excluding dlsym()bols of course).

Since you cannot dlsym() a type, this correctly ensures you CANNOT
catch an exception defined in a plugin. This cannot be permitted.
(Except with ... or a shared base of course!)

If you have a library L which throws E, then both L and the
application A MUST be linked against X, the library containing
the definition of E.

You do it like:

	X (contains E)
	|\
	| ------------------+
	|                   |
	L (throws E) --dl---A (catches E)

both L and A are *linked* against X. A dlopens L, and uses
the flags:

	dlopen(.., RTLD_LOCAL | RTLD_NOW)

There are a couple of exceptions to this rule, due to bad design
of C and C++: if you need to do malloc() or operator new() replacement
cruft, then you may need to use some linker trickery to work around
the faulty design.

The bottom line is that symbol sharing must be by design:
you either share a separate library between 2 clients using
static/load time linkage OR you use dlopen and dynamic/indirect
linkage. You should never do both at the same time (from
the one client). If you dlopen, the ONLY symbols you should be
able to get are with dlsym (unless you happen to also link against
it, which is possible but unusual).

-- 
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]