gpt4 book ai didi

c++ - dlclose() 不适用于工厂函数和函数中的复杂静态?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:40:51 35 4
gpt4 key购买 nike

我正在制作一个简单的插件框架,我希望能够在其中 dlopen() 一个共享库(即插件),检查并使用提供的任何工厂函数,并最终 dlclose() 它,不留痕迹.

我的工厂系统很简单,只有一个导出函数返回一个指向公共(public)基类的指针。为了检查插件是否已正确卸载,我有一个静态对象,其析构函数从主程序中设置了一个 bool 值。

这是主要程序:

// dltest.cpp follows. Compile with g++ -std=c++0x dltest.cpp -o dltest -ldl
#include <dlfcn.h>
#include <iostream>
using namespace std;
int main(int argc, char** argv)
{
if (argc > 1)
{
void* h = dlopen(argv[1], RTLD_NOW|RTLD_LOCAL);
if (!h)
{
cerr << "ERROR: " << dlerror() << endl;
return 1;
}
bool isFinilized = false;
*(bool**)dlsym(h, "g_finilized") = &isFinilized;
cout << boolalpha << isFinilized << endl;
if (dlclose(h))
{
cerr << "ERROR: " << dlerror() << endl;
return 2;
}
cout << boolalpha << isFinilized << endl;
}
return 0;
}

插件的代码是:

// libempty.cpp follows. Compile with g++ -std=c++0x libempty.cpp -o libempty.so -fPIC -shared
#include <iostream>
#include <vector>
using namespace std;
bool* g_finilized = nullptr;
struct Finilizer
{
~Finilizer()
{
cout << "~Finilizer()" << endl;
if (g_finilized) *g_finilized = true;
}
} g_finilizer;
class Base
{
public:
virtual void init() = 0;
};
class Foo: public Base
{
virtual void init()
{
static const vector<float> ns = { 0.f, 0.75f, 0.67f, 0.87f };
}
};
extern "C" __attribute__ ((visibility ("default"))) Base* newBase() { return new Foo; }

如果执行,输出为:

false
false
~Finilizer()

这表明对 dlclose() 的调用没有按预期工作,并且直到程序退出才卸载库。

但是,如果我们将 vector 移到函数外部,那么最后 8 行为:

class Foo: public Base
{
virtual void init()
{
}
};
static const vector<float> ns = { 0.f, 0.75f, 0.67f, 0.87f };
extern "C" __attribute__ ((visibility ("default"))) Base* newBase() { return new Foo; }

然后 dlclose() 正常运行,输出为:

false
~Finilizer()
true

如果 vector 留在函数中但没有导出工厂,则会生成相同的结果:

class Foo: public Base
{
virtual void init()
{
static const vector<float> ns = { 0.f, 0.75f, 0.67f, 0.87f };
}
};
//extern "C" __attribute__ ((visibility ("default"))) Base* newBase() { return new Foo; }

如果将 vector 替换为 C 数组,则会发现阳性结果:

class Foo: public Base
{
virtual void init()
{
static const float ns[] = { 0.f, 0.75f, 0.67f, 0.87f };
}
};
extern "C" __attribute__ ((visibility ("default"))) Base* newBase() { return new Foo; }

这是 GCC/Linux 中的错误吗?是否有任何解决方法可以在分解类的成员函数中静态声明复杂对象?

最佳答案

发生的事情是 libempty.so 中有一个 STB_GNU_UNIQUE 符号:

readelf -Ws libempty.so | grep _ZGVZN3Foo4initEvE2ns
91: 0000000000203e80 8 OBJECT UNIQUE DEFAULT 25 _ZGVZN3Foo4initEvE2ns
77: 0000000000203e80 8 OBJECT UNIQUE DEFAULT 25 _ZGVZN3Foo4initEvE2ns

问题是 STB_GNU_UNIQUE 符号的工作方式非常不直观,并且在 dlopen/dlclose 调用中持续存在。

使用该符号会强制 glibc 将您的库标记为不可卸载 here .

other surprises还有 GNU_UNIQUE 符号。如果您使用足够新的 gold 链接器,您可以使用 --no-gnu-unique 标志禁用 GNU_UNIQUE

关于c++ - dlclose() 不适用于工厂函数和函数中的复杂静态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11050693/

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