Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RTLD_LOCAL and dynamic_cast on Linux

Tags:

c++

linux

dlopen

We have a plugin that is constructed of a few shared libraries in our application that we need to update while the application is running. For performance reasons we load and start using the new plugin before unloading the old plugin and only when all threads are done using the old plugin we unload it. Since the libraries of the new plugin and the old plugin have the same symbols in them we dlopen() with RTLD_LOCAL. If we don't the new plugin call from internal functions by accident to symbols from the old plugin.

One library of the plugin does dynamic_cast() to an object that was created by another library of the plugin. This works on HP-UX, AIX, Solaris and Windows but not on Linux. As far as I can understand this is because all these OSs (compliers) use the name of the class to compare types (in the dynamic_cast()) but Linux uses name strings addresses to do this comparison (to improve performance) and since each library has its own type_info object (since it was loaded with RTLD_LOCAL) the addresses are different and therefore equal types seems to be non equal to the dynamic_cast().

Is there a way to do one of the following:

  • Make only the type_info objects be loaded as if RTLD_GLOBAL was supplied.
  • Make the compiler use class name comparison instead of type_info addresses for comparing between types.

? The compiler we are using is:

$ icpc -V
Intel(R) C++ Intel(R) 64 Compiler XE for applications running on Intel(R) 64, Version 12.0.0.084 Build 20101006
Copyright (C) 1985-2010 Intel Corporation.  All rights reserved.
like image 972
selalerer Avatar asked Feb 24 '23 03:02

selalerer


2 Answers

Ok, what we finally did is kind of worked around the problem.

We added to the classes that we want to dynamic_cast() two static functions:

static MyClass* doNew();
static MyClass* doDynCast(MyBase*);

These were implemented in the cpp file which kept the new, the dynamic_cast() and the type_info object in the same lib and thus making the dynamic_cast() work around the problem.

This solution was enough for our specific case but if anyone has a more general solution it will be welcomed.

Another option that we found is to put all the implementation of the class in the cpp file which make the typeinfo symbol be present only in one library and all other libraries reference it only. This results in a successful dynamic_cast().

like image 51
selalerer Avatar answered Feb 26 '23 21:02

selalerer


Unfortunately, because type_info structures are weak symbols local to the library that creates them, it's not easily possible to make dynamic_cast work. You might try manipulating where the class vtable (and type_info) is instantiated however; on GCC, this can be done by ensuring the first non-inline function in the class (in order of definition) is defined only in the common shared dependency library. If your class has no non-inline functions, create a dummy one just to force this generation to occur. Note however, that I haven't tested this and so can't guarantee that it will work. Additionally, this is compiler-dependent; I don't know what Intel's compiler does.

You could, of course, implement your own alternate dynamic casting mechanism using class names instead; there are a number of libraries which do this as well, such as Qt's qobject_cast.

like image 40
bdonlan Avatar answered Feb 26 '23 21:02

bdonlan