首页 > 解决方案 > 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().

标签: c++linuxpluginsdlopen

解决方案


是的,dlclose由于您指定的原因,从库函数调用会出现段错误:

$ 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

目前尚不清楚为什么它在您的特定情况下有效(您的库可能会导出GNU_UNIQUE符号,库可能会被dlopen编辑两次等)。


推荐阅读