繁体   English   中英

dlmopen 和 C++ 库

[英]dlmopen and C++ libraries

(这大概是一个相当高级的问题,对此感到抱歉:-))

我有一个问题,我需要将插件(共享库)加载到应用程序中,但该插件可能使用与应用程序使用的库版本二进制不兼容的库。 我的想法是使用 dlmopen() 并将插件加载到自己的命名空间中。 我希望获得二进制不兼容库的两个单独副本(以及任何其他常见依赖项,即使二进制兼容)。

这似乎在一定程度上起作用,但在某些情况下,在调用静态对象的构造函数时,我在 glibc 内部深处出现了段错误(这是我在调试器中发现的)。

我做了一个最小的例子来重现这个问题,可以在 github 上找到: https : //github.com/mhier/segregatedLinkingExample

该示例使用 libxml++ 作为外部通用 C++ 库,因此您需要安装其开发包。 运行“mk.sh”进行编译,然后运行“main”。 然后它会崩溃(至少在 Ubuntu 16.04 和 18.04 上是这样)。 如果您删除“-DWITH_CRASH”,它不再崩溃。

WITH_CRASH 编译开关允许在主可执行文件中使用 if libxml++。 它总是在插件库 libC 中使用。 我看到崩溃的主要可执行文件和插件中仅使用了 libxml++。 在这种情况下,“使用”就像从中派生出一个虚拟类,并确保通过实现构造函数/析构函数来真正生成派生类的代码。 它甚至不执行插件中的代码(除了通过 dl_init -> 静态对象的构造函数等)。

我在 Internet 上找不到关于 dlmopen 的太多信息。 我没有发现任何指向正确方向的错误报告。 有没有人使用 dlmopen 和 C++ 库的新命名空间? 非常欢迎任何形式的输入如何从这一点继续!

该问题与 C++ 无关。

这是libpthreads的glibc版本中的一个bug,导致加载了dlmopen的库返回pthread_key_create的重复项,导致线程特定的存储被破坏(相同的key意味着相同的内存位置,就像malloc多次返回相同的内存区域一样) .

这立即崩溃的原因是因为 libglib 在其加载函数中大量使用了线程特定的存储。

详细地说,问题是直接使用 __pthread_keys 全局变量,而该变量应该通过线程描述符 (THREAD_SELF) 加载,从而确保线程本地键在 libpthread 的所有实例共享的结构中分配。

详情见源码: https : //sourceware.org/git/?p=glibc.git;a=blob;f=nptl/pthread_key_create.c;h=a584db412b7b550fa7f59e445155dbfddaeb1d23;hb=HEAD

报告给 glibc: https ://sourceware.org/bugzilla/show_bug.cgi ? id =26955

同样在 gdb 中调试这种东西时,提示获取调试符号:

  • 检查 /proc/$pid/maps 以找出 dlmopen 加载库的位置
  • 找到库的入口点(例如 readelf -h /usr/lib/x86_64-linux-gnu/libglib-2.0.so )
  • 在 gdb 中使用 add-symbol-file 加载符号。
    • 作为文件名只需指定库文件,如果您安装了调试符号,gdb会以正常方式找到它们 - 不要尝试直接指定符号文件
    • 地址是来自 /proc/$pid/maps 的加载地址 + 入口点地址

所以似乎答案是不这样做。 dlmopen 似乎与 C++ 有问题,这可能导致未定义的行为。 据推测,命名空间并没有完全修复 ODR 违规。

我承认,这个答案是我的主观看法。 我还没有找到很多关于将 dlmopen 用于 C++ 库的好资源。 因此我的结论是不要使用它,因为我需要它可靠地工作。 我看到了非常奇怪的效果,例如,如果我将共享库链接到特定的第三方库(即使不使用它),我在问题中的示例再次起作用。 除非我能理解这些影响,否则我不会相信解决方案(因为它可能会意外地起作用)。

dlmopen() 可能在其他上下文中工作,例如,如果一个人同时控制应用程序和共享库,并且可以测试它是否正确加载。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM