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