std::function and shared object libraries
Jonathan Wakely
jwakely.gcc@gmail.com
Sat Jun 13 11:59:00 GMT 2015
On 13 June 2015 at 04:39, Gabriel Marcano <gabemarcano@yahoo.com> wrote:
> I've been using std::function with GCC 5.1 in c++11 mode for registering some callbacks in a program. The program also loads in a shared library as a plugin, and is also allowed to register callbacks. Everything works as expected, but upon terminating the program segfaults. I traced the problem to the std::function destructor, which is using, in my case, an invalid _M_manager handle (which causes the segfault). Based on some further testing, it seems the handle is invalidated by the plugin being unloaded before the std::function destructor is called. If I switch the order of destruction/unloading, the program finishes without problems.
>
> I was able to reproduce the problem in a simple setup, which I'm inlining below. Simply run the Makefile, and then run the `test` executable. It should segfault (at least it does on my amd64 Linux system).
>
>
> Is std::function supposed to be that sensitive to shared libraries? Am I missing something from the documentation that explains this behavior? Thank you for any insight on the issue!
I don't see any way to avoid this, you're taking a pointer to code
defined in the shared library, then unloading the shared library, then
using the code that was just unloaded.
This isn't really a problem with std::function, it's just that
std::function makes it a bit easier to do, but your program is
equivalent to this:
// main.cpp
#include <dlfcn.h>
using f_t = void (*)();
extern "C" void load(f_t& fun);
int main()
{
using sh_f = decltype(&load);
void* lib = dlopen("./shared.so", RTLD_GLOBAL);
sh_f sh = (sh_f)dlsym(lib, "load");
f_t f;
sh(f);
dlclose(lib);
f();
}
// shared.cpp
void shared() { }
using f_t = void (*)();
extern "C" void load(f_t& fun)
{
fun = shared;
}
What happens in the std::function case is that the statement "fun =
shared;" instantiates a function template and stores a pointer to that
function in the fun._M_manager member. In the std::function destructor
that function is called. Boom.
There is no way for the C++ runtime to avoid this, because it has no
way of knowing a priori what types you are going to store in a
std::function, so it can't know which specializations of the function
template will be needed.
More information about the Gcc-help
mailing list