libpthread.so 在 'dlclose()' 之后继续使用 TLS 空间和 DL 命名空间
libpthread.so continues to use TLS space and DL namespaces after `dlclose()`
我正在处理一个需要将基于 Rust 的插件(共享对象)任意加载/卸载到隔离的动态库命名空间中的项目。
我使用dlmopen(LM_ID_NEWLM, "rust-plugin.so", RTLD_LAZY)
为共享对象创建一个新的命名空间。当不再需要共享对象时,我调用dlclose()
。
不幸的是,我发现即使我dlclose()
一次只有一个共享对象有效,在dlmopen()
14 个 Rust 插件对象后,我也会收到错误:
dlmopen(rust-plugin.so) failed: /lib/x86_64-linux-gnu/libc.so.6: cannot allocate memory in static TLS block
在此故障后继续尝试dlmopen()
会导致分段错误并no more namespaces available for dlmopen()
。
我似乎已经将问题隔离为 Rust 共享对象的libpthread.so
依赖关系。其他共享对象依赖项,如libgcc_s.so.1
(以及我尝试过的任何 .so 文件,就此而言)可以通过以下代码无限期地打开和关闭,而在我打开和关闭它 14 次后libpthread.so
错误。
#include <link.h>
#include <stdio.h>
#include <dlfcn.h>
#include <cstdlib>
void load(char const *file) {
void *handle_ = dlmopen(LM_ID_NEWLM, file, RTLD_LAZY);
if (!handle_) {
printf("dlmopen(%s) failed: %sn", file, dlerror());
exit(1);
}
if (dlclose(handle_) != 0) {
exit(2);
}
}
int main() {
void *handle_;
for (int i = 0; true; i++) {
printf("%dn", i);
load("libpthread.so.0");
}
}
有什么方法可以让libpthread正确清理,这样我就可以避免这个问题?
libpthread.so.0
NODELETE
标志:
readelf -d /lib/x86_64-linux-gnu/libpthread.so.0 | grep NODELETE
0x000000006ffffffb (FLAGS_1) Flags: NODELETE INITFIRST
这使得dlclose()
成为无操作。另请参阅此答案。
鉴于dlclose()
是无操作的,其他一切都有意义:GLIBC 总共配置了 16 个加载程序命名空间,其中一个保留给主应用程序。一旦您调用dlmopen
(不调用dlclose
)15 次,您将耗尽所有尝试,后续尝试将失败并no more namespaces available
。
用NODELETE
标记libpthread
是有意义的:一旦它出现在图片中,它就会从根本上改变 GLIBC 操作(例如malloc
开始获取锁,errno
切换到线程本地等)。
有什么方法可以让libpthread正确清理,这样我就可以避免这个问题?
我相信对您来说唯一现实的选择是尽量避免依赖插件中的libpthread
。
您可以执行的其他操作:
- 打开针对 GLIBC 的错误(但您可能会等待很长时间才能修复它)。我不确定从非默认加载程序范围卸载
libpthread
的含义是什么;也许它应该是可卸载的, - 构建你自己的 libpthread.so,与系统相同,但没有
-z,nodelete
链接器标志,并安排将此libpthread.so.0
作为插件依赖项加载(确保此版本与系统版本保持同步,否则您将看到很难调试崩溃)。
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 命名空间中具有.h和.cpp文件的类
- 从父命名空间重载类型
- 当在同一名称空间中有两个具有相同签名的函数时,会发生什么
- 在命名空间中定义函数还是限定函数
- C++:对不存在的命名空间使用命名空间指令
- 通过继承类使用来自不同命名空间的运算符
- 使用命名空间时出现多个定义错误
- OpenGL相机和相机空间转型的困惑
- CUDA内核和数学函数的显式命名空间
- 打印第二列时的2d字符矢量打印空间
- 嵌套的匿名命名空间
- CMakeLists.txt中的命名空间表示法
- OpenSSL TLS服务器-使用客户端证书白名单
- 类是C++中的命名空间吗
- 在命名空间中使用全局命名空间中的函数
- 如何使 std::sort 在 std::swap 和我的命名空间的模板化交换之间没有名称冲突?
- '使用命名空间{嵌套在另一个命名空间中的某个命名空间}"
- 为什么 openmp 的并行不适用于矢量化色彩空间转换?
- libpthread.so 在 'dlclose()' 之后继续使用 TLS 空间和 DL 命名空间