破坏两个共享对象之间 common 类 内的静态成员?
Destruction of static members inside common classes between two shared objects?
我有以下层次结构:
- 类 具有多个静态
std::map
,在 cpp 中初始化如下
std::map<int, string> ClassA::MyStaticMap = ClassA::InitializeMyStaticMap()
- 包含这些 类.
的共享对象 libfoo.so
- 包含这些 类.
的共享对象 libbar.so
- 利用这两个库的应用程序。
我在应用程序中这些地图的析构函数中崩溃了。默认情况下符号是可见的,我没有更改可见性设置。
当我使用 g++ 的 -s
选项从 so 中删除符号时,崩溃消失了。
我对如何解决这个问题有一个设想,不确定哪个更好:
- 继续剥离符号 table,(不确定是否有更多我应该注意的含义)。
- 将这些共同的东西移动到第 3 个共享对象中,并使
libfoo.so
和 libbar.so
动态地 link 反对。
哪个更好?还有为什么会发生崩溃,我试图了解发生了什么但我做不到。
编辑 1
GCC 版本:4.3.3
目标平台:Linux - RH 7.5
简短回答:不要依赖从 DSO 导出的代码中的全局变量。
// from lib foo
class B {
public:
B(std::map<int, string>& map)
: a_map_ref(map) {}
std::map<int, string>& a_map_ref;
};
// from lib bar
class C {
public:
C(std::map<int, string>& map)
: a_map_ref(map) {}
std::map<int, string>& a_map_ref;
};
// in your exe
int main() {
// Here's my map. I know where it is. I can manage its lifetime
std::map<int, string> a_map;
// now I don't care about libFoo initialisation
{
loadLibFooDSO();
{
B* b = new B(a_map);
// do thing
delete b;
}
unloadLibFooDSO();
}
// now I don't care about libBar initialisation
{
loadLibBarDSO();
{
C* c = new C(a_map);
// do thing
delete c;
}
unloadLibBarDSO();
}
// because my map will correctly be cleaned up on exit
return 0;
}
长答案,有很多原因可能导致此问题。您没有提供有关 ClassA::MyStaticMap 如何链接到程序中的任何信息,因此或多或少是不可能说的。
如果它在静态库中,那么 libfoo 和 libbar 都会有自己的 ClassA::MyStaticMap 副本。无论哪个库首先加载,最终都将拥有 ClassA::MyStaticMap 的实例(另一个将简单地使用现有符号)。因此,如果首先加载 libfoo,则 libber 将使用 libfoo 版本的变量。如果 libfoo 先被销毁,libbar 将尝试销毁一个已经被销毁的变量。
简单的解决方案是:不要从 DSO 全局导出数据。仅将 DSO 接口保留为函数,您通常就可以了(ish,有一些注意事项)。
还有其他可能导致崩溃的原因,请选择以下任一原因:
- 一个 DSO 是在启用调试的情况下构建的,另一个是发布构建。
- 一个 DSO 使用 C++98 构建,另一个使用 C++17。
- 一个 DSO 是用 VC++ 构建的,另一个是 clang。
我有以下层次结构:
- 类 具有多个静态
std::map
,在 cpp 中初始化如下
std::map<int, string> ClassA::MyStaticMap = ClassA::InitializeMyStaticMap()
- 包含这些 类. 的共享对象
- 包含这些 类. 的共享对象
- 利用这两个库的应用程序。
libfoo.so
libbar.so
我在应用程序中这些地图的析构函数中崩溃了。默认情况下符号是可见的,我没有更改可见性设置。
当我使用 g++ 的 -s
选项从 so 中删除符号时,崩溃消失了。
我对如何解决这个问题有一个设想,不确定哪个更好:
- 继续剥离符号 table,(不确定是否有更多我应该注意的含义)。
- 将这些共同的东西移动到第 3 个共享对象中,并使
libfoo.so
和libbar.so
动态地 link 反对。
哪个更好?还有为什么会发生崩溃,我试图了解发生了什么但我做不到。
编辑 1
GCC 版本:4.3.3
目标平台:Linux - RH 7.5
简短回答:不要依赖从 DSO 导出的代码中的全局变量。
// from lib foo
class B {
public:
B(std::map<int, string>& map)
: a_map_ref(map) {}
std::map<int, string>& a_map_ref;
};
// from lib bar
class C {
public:
C(std::map<int, string>& map)
: a_map_ref(map) {}
std::map<int, string>& a_map_ref;
};
// in your exe
int main() {
// Here's my map. I know where it is. I can manage its lifetime
std::map<int, string> a_map;
// now I don't care about libFoo initialisation
{
loadLibFooDSO();
{
B* b = new B(a_map);
// do thing
delete b;
}
unloadLibFooDSO();
}
// now I don't care about libBar initialisation
{
loadLibBarDSO();
{
C* c = new C(a_map);
// do thing
delete c;
}
unloadLibBarDSO();
}
// because my map will correctly be cleaned up on exit
return 0;
}
长答案,有很多原因可能导致此问题。您没有提供有关 ClassA::MyStaticMap 如何链接到程序中的任何信息,因此或多或少是不可能说的。
如果它在静态库中,那么 libfoo 和 libbar 都会有自己的 ClassA::MyStaticMap 副本。无论哪个库首先加载,最终都将拥有 ClassA::MyStaticMap 的实例(另一个将简单地使用现有符号)。因此,如果首先加载 libfoo,则 libber 将使用 libfoo 版本的变量。如果 libfoo 先被销毁,libbar 将尝试销毁一个已经被销毁的变量。
简单的解决方案是:不要从 DSO 全局导出数据。仅将 DSO 接口保留为函数,您通常就可以了(ish,有一些注意事项)。
还有其他可能导致崩溃的原因,请选择以下任一原因:
- 一个 DSO 是在启用调试的情况下构建的,另一个是发布构建。
- 一个 DSO 使用 C++98 构建,另一个使用 C++17。
- 一个 DSO 是用 VC++ 构建的,另一个是 clang。