pro*_*ist 5 c++ linux pthreads dynamic-linking dlopen
我正在开发一个项目,该项目需要将基于 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
Run Code Online (Sandbox Code Playgroud)
dlmopen()在此失败后继续尝试导致分段错误和no more namespaces available for dlmopen().
我似乎已将问题与libpthread.soRust 共享对象的依赖关系隔离。其他共享对象依赖项libgcc_s.so.1(以及我尝试过的任何 .so 文件,就此而言)可以通过以下代码无限期地打开和关闭,而libpthread.so在我打开和关闭它 14 次后会出现错误。
#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: %s\n", file, dlerror());
exit(1);
}
if (dlclose(handle_) != 0) {
exit(2);
}
}
int main() {
void *handle_;
for (int i = 0; true; i++) {
printf("%d\n", i);
load("libpthread.so.0");
}
}
Run Code Online (Sandbox Code Playgroud)
有什么方法可以让 libpthread 正确清理,这样我就可以避免这个问题吗?
libpthread.so.0有NODELETE标志:
readelf -d /lib/x86_64-linux-gnu/libpthread.so.0 | grep NODELETE
0x000000006ffffffb (FLAGS_1) Flags: NODELETE INITFIRST
Run Code Online (Sandbox Code Playgroud)
这使得dlclose()它成为无操作。另请参阅此答案。
鉴于这dlclose()是无操作,其他一切都有意义:GLIBC 总共配置了 16 个加载器命名空间,其中之一为主应用程序保留。一旦您调用dlmopen(不调用dlclose) 15 次,您就会耗尽所有这些,并且后续尝试会失败并显示no more namespaces available。
标记libpthread为NODELETE有意义:一旦它出现在图中,它就会从根本上改变 GLIBC 操作(例如malloc开始获取锁、errno切换到线程本地等)。
有什么方法可以正确清理 libpthread 以避免此问题吗?
我相信您唯一现实的选择是尝试避免对libpthread插件的依赖。
您可以做的其他事情:
libpthread从非默认加载器范围卸载的影响是什么;也许它应该是可卸载的,-z,nodelete链接器标志,并安排将其libpthread.so.0作为插件依赖项加载(确保此版本与系统版本保持同步,否则您将很难看到调试崩溃)。| 归档时间: |
|
| 查看次数: |
621 次 |
| 最近记录: |