C++强制卸载共享库

C++ force unloading shared library

我正在尝试创建一个可多次重新加载共享库的应用程序。但在某个时间点,dlmopen 失败并出现错误

/usr/lib/libc.so.6: cannot allocate memory in static TLS block

这是重现此问题的最少代码:

#include <dlfcn.h>
#include <cstdio>
#include <vector>

int main() {
  for (int i = 0; i < 100; ++i) {
    void *lib_so = dlmopen(LM_ID_NEWLM, "lib.so", RTLD_LAZY | RTLD_LOCAL);
    if (lib_so == NULL) {
      printf("Iteration %i loading failed: %s\n", i, dlerror());
      return 1;
    }
    dlclose(lib_so);
  }

  return 0;
}

和空lib.cpp,用

编译
g++ -rdynamic -ldl -Wl,-R . -o test main.cpp
g++ -fPIC -shared lib.cpp -o lib.so

更新

好像连一个线程都崩溃了。问题是:如何强制卸载库或销毁使用 LM_ID_NEWLM 创建的未使用的命名空间?

旧的 glibc 版本可能有一些与此相关的错误:

https://bugzilla.redhat.com/show_bug.cgi?id=89692 https://sourceware.org/bugzilla/show_bug.cgi?id=14898

您使用的是什么版本?尝试使用较新的 glibc 版本,您的代码在我的计算机上运行良好 (glibc 2.23)。

进程可用的 link 映射名称空间的数量存在内置限制。这在评论中记录得很差:

The glibc implementation supports a maximum of 16 namespaces

在手册页中。

创建 link 地图命名空间后,将无法通过任何 API 支持 'erasing' 它。这就是它的设计方式,如果不编辑 glibc 源代码并添加一些挂钩,就没有真正的方法来解决这个问题。

使用命名空间重新加载库实际上并不是重新加载库 - 您只是加载库的新副本。这是命名空间的用例之一——如果您多次尝试 dlopen 同一个库,您将获得同一个库的相同句柄;但是,如果您在不同的命名空间中加载第二个实例,您将不会获得相同的句柄。如果要完成重新加载,您需要使用 dlclose 卸载库,这将在释放对库的最后一个剩余引用后卸载库。

如果你想尝试 'force unload' 一个库,那么你可以尝试发出多个 dlclose 调用直到它卸载;但是,如果您不知道库做了什么(例如生成的线程),那么在这种情况下可能无法防止崩溃。