(这大概是一个相当高级的问题,对此表示抱歉:-))
我有一个问题,我需要将插件(共享库)加载到应用程序中,但是该插件可能使用的二进制库与应用程序使用的库的版本不兼容。我的想法是使用dlmopen()并将插件加载到其自己的名称空间中。我希望获得二进制不兼容库的两个单独副本(以及二进制兼容的任何其他常见依赖项)。
这似乎可以达到一定程度,但是在某些情况下,在静态对象的构造函数被调用时(这是我在调试器中发现的),我在glibc的内部有了一个段错误。 >
我做了一个最小的例子来重现该问题,可以在github上找到:https://github.com/mhier/segregatedLinkingExample
该示例使用libxml ++作为外部通用C ++库,因此您将需要安装其开发包。运行“ mk.sh”进行编译,然后运行“ main”。然后它将崩溃(至少在Ubuntu 16.04和18.04上会崩溃)。如果您删除“ -DWITH_CRASH”,它将不再崩溃。
WITH_CRASH编译开关允许在主可执行文件中使用libxml ++。它始终在插件库libC中使用。主可执行文件和插件都只使用libxml ++,我看到崩溃了。在这种情况下,“使用”只不过是从虚拟类派生一个虚拟类,并确保通过实现构造函数/析构函数确实为派生类生成了代码。它甚至没有在插件中执行代码(除了通过dl_init->静态对象的构造函数等)。
我在Internet上找不到关于dlmopen的更多信息。我没有找到指向正确方向的错误报告。有没有人使用dlmopen和C ++库的新命名空间?任何形式的输入从现在开始都非常欢迎!
答案 0 :(得分:0)
所以看来答案是不这样做。 dlmopen似乎与C ++有关,可能导致未定义的行为。大概是因为名称空间无法完全解决ODR违规问题。
我承认,这个答案是我的主观看法。我没有找到关于将dlmopen用于C ++库的许多很好的资源。因此,我的结论是不使用它,因为我需要它可靠地工作。我看到了非常奇怪的效果,例如如果我将共享库链接到特定的第三方库(即使不使用它),我在问题中的示例也可以再次使用。除非我能理解这些影响,否则我将不信任一个解决方案(因为它可能会偶然起作用)。
dlmopen()可能在其他情况下(例如是否可以同时控制应用程序和共享库,并可以测试它是否正确加载。
答案 1 :(得分:0)
问题与C ++无关。
这是libpthreads的glibc版本中的一个错误,该错误导致装载dlmopen的库返回pthread_key_create的重复项,从而导致线程专用存储被破坏(相同的键表示相同的内存位置,就像malloc返回相同的内存区域一样)多次)。
立即崩溃的原因是因为libglib在其加载函数中已经大量使用了特定于线程的存储。
详细来说,问题在于直接使用__pthread_keys全局变量,而应该通过线程描述符(THREAD_SELF)加载它,从而确保在所有libpthread实例共享的结构中分配线程本地键。
已报告给glibc:https://sourceware.org/bugzilla/show_bug.cgi?id=26955
在gdb中调试这种东西时,提示获取调试符号: