[英]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 中调试这种东西时,提示获取调试符号:
所以似乎答案是不这样做。 dlmopen 似乎与 C++ 有问题,这可能导致未定义的行为。 据推测,命名空间并没有完全修复 ODR 违规。
我承认,这个答案是我的主观看法。 我还没有找到很多关于将 dlmopen 用于 C++ 库的好资源。 因此我的结论是不要使用它,因为我需要它可靠地工作。 我看到了非常奇怪的效果,例如,如果我将共享库链接到特定的第三方库(即使不使用它),我在问题中的示例再次起作用。 除非我能理解这些影响,否则我不会相信解决方案(因为它可能会意外地起作用)。
dlmopen() 可能在其他上下文中工作,例如,如果一个人同时控制应用程序和共享库,并且可以测试它是否正确加载。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.