Joshua Chia
Joshua Chia

Reputation: 1978

Is calling dlclose() from code loaded by the corresponding dlopen() OK?

The question is as in the title and the following is the background:

On Linux, I'm trying to use dlopen() etc to build a C++ .so plugin framework that has a minimal and clean interface. That means:

  1. Loading the plugin and creating a (C++) singleton object from the plugin simply involves calling a function makePluginObject() with a path to the .so file being loaded and getting back a pointer to the object. Under the hood, this function calls dlopen() followed by the actual object allocation & construction. The object is of a C++ class whose implementation is in the .so.
  2. Later, the user can just delete (calling dtor) the pointer to do all the necessary cleanup, including dlclose(), which is done by the dtor. This would be implemented by calling dlclose() in the object's dtor. (Under the hood, the handle from dlopen() was passed to the object during makePluginObject().) Crucially, there is no additional shutdown/teardown function for the user to explicitly call.

The above design probably means that the code calling dlclose() is in the .so being dlopen'ed. The key question is this: Is it OK for code to call dlclose() on itself? I wonder because a naive implementation of dlclose() would unmap from memory the code that is still being run during object destruction.

It's important that the user interface remains this simple. The user just needs to call makePluginObject() and delete the resulting pointer when he is done. If a teardown function is introduced that the user has to explicitly call after deleting the object, then the interface is much heavier and the burden on the user is much more. I know how to do things if an explicit teardown function is allowed and this question is not about that use case.

In my experiments, there were no crashes, but it seemed that dlclose() didn't really do anything because valgrind reported a lot of reachable memory associated with my call to dlopen().

Upvotes: 2

Views: 814

Answers (1)

yugr
yugr

Reputation: 21955

Yes, calling dlclose from library function will case a segfault, for the reasons you specified:

$ cat main.c
#include <dlfcn.h>
int main() {
  void *h = dlopen("./liblib.so", RTLD_LAZY | RTLD_GLOBAL);
  int (*foo)(void *) = dlsym(h, "foo");
  foo(h);
  return 0;
}
[y.gribov@link ~]$ cat lib.c
#include <dlfcn.h>
#include <stdio.h>
int foo(void *h) {
  printf("Before dlclose\n");
  dlclose(h);
  printf("After dlclose\n");
  return 10;
}
$ gcc main.c -ldl
$ gcc -o liblib.so lib.c -shared -fPIC -ldl
$ ./a.out
Before dlcose
Segmentation fault

It's unclear why it works in your particular case (your library may export GNU_UNIQUE symbol, library may be dlopened twice, etc.).

Upvotes: 2

Related Questions