gpt4 book ai didi

c++ - 静态对象在 dlclose() 之前被破坏

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:20:26 28 4
gpt4 key购买 nike

我正在从事一个跨平台项目,该项目由多个库组成,根据运行时条件动态地相互加载和卸载。目前我观察到一个崩溃,这似乎是由共享库之一中的静态对象在使用 dlclose() 卸载共享库之前被销毁这一事实引起的。这看起来很奇怪,对我来说更像是一个错误。

为了调查这个问题,我创建了一个简单的项目,它包含三个源文件:main.cpp、lib1.cpp 和 lib2.cpp(分别用于可执行文件和两个库)。主可执行文件动态加载 lib1,而 lib1 又动态加载 lib2。

主要.cpp:

Logger mainGlobal("mainGlobal");

int main(int argc, char * argv[])
{
Logger mainFunction("mainFunction");
try
{
Logger mainTry("mainTry");
libutil::AutoLib lib("lib1");
lib.call("loadLib2");
}
catch (std::exception & e)
{
std::cerr << "Fatal: " << e.what() << std::endl;
}
std::cout << "Exiting main" << std::endl;
}

lib1.cpp:

Logger lib1Global("lib1Global");

std::auto_ptr<libutil::AutoLib> lib2;

DLL_EXPORT void loadLib2()
{
std::cout << "loadLib2" << std::endl;
lib2.reset(new libutil::AutoLib("lib2"));
}

lib2.cpp:

Logger lib2Global("lib2Global");

Logger 是一个简单的结构,它只记录其构造函数和析构函数。 libutil::AutoLib 是一个共享库加载器,它在其 ctor 中调用 dlopen(path, RTLD_LAZY),并在其 dtor 中调用 dlclose() , 并允许调用从共享库导出的函数。这些类的代码很简单,但如果需要,我也可以将其发布在这里。

长话短说,如果我调用主可执行文件,我会看到以下日志:

mainGlobal ctor
mainFunction ctor
mainTry ctor
Loading library lib1.so
lib1Global ctor
dlopen(lib1.so) returned 0x14cd050
Library lib1.so loaded with handle 0x14cd050
Calling loadLib2 in library 0x14cd050
loadLib2
Loading library lib2.so
lib2Global ctor
dlopen(lib2.so) returned 0x14cd710
Library lib2.so loaded with handle 0x14cd710
Unloading library 0x14cd050
Calling dlclose(0x14cd050)
Library unloaded 0x14cd050
mainTry dtor
Exiting main
mainFunction dtor
lib2Global dtor
Unloading library 0x14cd710
Calling dlclose(0x14cd710)
Library unloaded 0x14cd710
lib1Global dtor
mainGlobal dtor

请注意 lib2Global dtor 行在 Calling dlclose(0x14cd710) 行之前。

那么问题来了,这是错误还是正确的行为?

SO 中有关于静态对象在 dlclose() 之后没有被销毁的问题,但我没有发现任何关于相反情况的问题。

我使用的是 GCC 5.4.0-6ubuntu1~16.04.10。

最佳答案

感谢 Davis Herring 的提示,我找到了原因。所以有点在内存中保存 lib1.so,不允许它卸载。结果是,lib1.so 调用了一个 inline 函数,其中包含 static const 变量,这使得 gcc 为此创建了 STB_GNU_UNIQUE 绑定(bind)多变的。这反过来有效地使 lib1.so 无法加载,即使它是使用 RTLD_LOCAL 加载的。因此,要解决此问题,我可以从变量定义中删除 static 限定符,或者从函数定义中删除 inline 限定符,或者使用 -fno- gnu-unique g++ 标志。在我这样做之后,问题就消失了:

mainGlobal ctor
mainFunction ctor
mainTry ctor
Loading library lib1.so
lib1Global ctor
dlopen(lib1.so) returned 0x1cfe050
Library lib1.so loaded with handle 0x1cfe050
Calling loadLib2 in library 0x1cfe050
loadLib2
Loading library lib2.so
lib2Global ctor
dlopen(lib2.so) returned 0x1cfe710
Library lib2.so loaded with handle 0x1cfe710
Unloading library 0x1cfe050
Calling dlclose(0x1cfe050)
Unloading library 0x1cfe710
Calling dlclose(0x1cfe710)
Library unloaded 0x1cfe710
lib1Global dtor
lib2Global dtor
Library unloaded 0x1cfe050
mainTry dtor
Exiting main
mainFunction dtor
mainGlobal dtor

这里是 GNU GCC 帮助的摘录,关于这个:

-fno-gnu-unique
On systems with recent GNU assembler and C library, the C++ compiler
uses the STB_GNU_UNIQUE binding to make sure that definitions of template
static data members and static local variables in inline functions are unique
even in the presence of RTLD_LOCAL ; this is necessary to avoid problems
with a library used by two different RTLD_LOCAL plugins depending on a definition
in one of them and therefore disagreeing with the other one about the binding of
the symbol. But this causes dlclose to be ignored for affected DSOs; if your
program relies on reinitialization of a DSO via dlclose and dlopen , you can use
-fno-gnu-unique .

Here是一个相关问题的问题。

关于c++ - 静态对象在 dlclose() 之前被破坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56808889/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com