我建立了一个共享库" libMyLibrary.so"与班级" MyClass"它包含一个类型为" MyClass"的静态变量。 然后我构建了一个可执行文件" MyLibraryTest"我链接到" libMyLibrary.so"。 主程序使用" dlopen"动态加载" .so"作为论据。
构建时,库和可执行文件在目录中生成,例如" buildDir / bin"。 然后我将库安装到" installDir / lib"并将可执行文件放入" installDir / bin" (从可执行文件中删除运行时路径)。
当我运行" buildDir / MyLibraryTest buildDir / MyLibrary.so"使用LD_LIBRARY_PATH = buildDir,一切都很好。
但是当我运行" buildDir / MyLibraryTest installDir / lib / MyLibrary.so"使用LD_LIBRARY_PATH = installDir / lib,会发生一件非常奇怪的事情: - 静态变量的构造函数被称为两次(一次在dlopen之前,一次在dlopen期间) - 在执行结束时,析构函数被调用两次,这会导致崩溃。
这是我的代码:
MyClass.h
#ifndef _MyClass_h__
#define _MyClass_h__
#include <string>
class MyClass
{
private:
static MyClass myStaticObjOfMyClass;
public:
MyClass(const std::string& name, bool trace);
virtual ~MyClass();
private:
std::string myName;
bool myTrace;
};
#endif // _MyClass_h__
MyClass.cpp
#include "MyClass.h"
#include <iostream>
MyClass MyClass::myStaticObjOfMyClass("myStaticObjOfMyClass", true);
MyClass::MyClass(const std::string& name, bool trace) : myName(name), myTrace(trace)
{
if (myTrace) std::cout << "MyClass::MyClass(name=" << myName << ", address=" << this << ")" << std::endl;
}
MyClass::~MyClass()
{
if (myTrace) std::cout << "MyClass::~MyClass(name=" << myName << ", address=" << this << ")" << std::endl;
}
MyLibraryTest.cpp
#include <MyClass.h>
#include <iostream>
#include <string>
#include <dlfcn.h>
int main(int argc, char* argv[])
{
const std::string sharedLibraryFullName((const char*)argv[1]);
// std::cout << "Try to load library " << sharedLibraryFullName << std::endl;
void* handle = NULL;
std::cout << "dlopen(" << sharedLibraryFullName << ")" << std::endl;
handle = dlopen(sharedLibraryFullName.c_str(), RTLD_LAZY | RTLD_GLOBAL);
if (handle == NULL)
{
std::cout << "ERROR : Could not load shared library " << sharedLibraryFullName << std::endl;
}
else
{
std::cout << "OK, shared library " << sharedLibraryFullName << " is now loaded" << std::endl;
}
}
以下是编译和链接命令:
/usr/local/bin/g++ -DMyLibrary_DEFINED -DMyLibrary_EXPORTS -O3 -DNDEBUG -fPIC -o CMakeFiles/MyLibrary.dir/MyClass.cpp.o -c MyClass.cpp
/usr/local/bin/g++ -fPIC -O3 -DNDEBUG -shared -Wl,-soname,libMyLibrary.so -o ../bin/libMyLibrary.so CMakeFiles/MyLibrary.dir/MyClass.cpp.o
最后这是第二种情况(静态变量的重复初始化):
MyClass::MyClass(name=myStaticObjOfMyClass, address=0x7fa710cabb40)
dlopen(/tmp/Install/MyLibraryTest/lib/libMyLibrary.so)
MyClass::MyClass(name=myStaticObjOfMyClass, address=0x7fa710cabb40)
OK, shared library /tmp/Install/MyLibraryTest/lib/libMyLibrary.so is now loaded
MyClass::~MyClass(name=myStaticObjOfMyClass, address=0x7fa710cabb40)
MyClass::~MyClass(name=��ObjOfMyClass, address=0x7fa710cabb40)
*** glibc detected *** /tmp/Build/MyLibraryTest/Release/bin/MyLibraryTest: double free or corruption (fasttop): 0x0000000000cfb330 ***
======= Backtrace: =========
/lib64/libc.so.6[0x322f275dee]
/lib64/libc.so.6[0x322f278c3d]
/lib64/libc.so.6(__cxa_finalize+0x9d)[0x322f235d2d]
/tmp/Build/MyLibraryTest/Release/bin/libMyLibrary.so(+0x1076)[0x7fa710aab076]
======= Memory map: ========
00400000-00402000 r-xp 00000000 fd:00 1325638 /tmp/Build/MyLibraryTest/Release/bin/MyLibraryTest
00601000-00602000 rw-p 00001000 fd:00 1325638 /tmp/Build/MyLibraryTest/Release/bin/MyLibraryTest
00ce9000-00d1b000 rw-p 00000000 00:00 0 [heap]
322ee00000-322ee20000 r-xp 00000000 fd:00 545634 /lib64/ld-2.12.so
322f020000-322f021000 r--p 00020000 fd:00 545634 /lib64/ld-2.12.so
322f021000-322f022000 rw-p 00021000 fd:00 545634 /lib64/ld-2.12.so
322f022000-322f023000 rw-p 00000000 00:00 0
322f200000-322f38a000 r-xp 00000000 fd:00 545642 /lib64/libc-2.12.so
322f38a000-322f58a000 ---p 0018a000 fd:00 545642 /lib64/libc-2.12.so
322f58a000-322f58e000 r--p 0018a000 fd:00 545642 /lib64/libc-2.12.so
322f58e000-322f590000 rw-p 0018e000 fd:00 545642 /lib64/libc-2.12.so
322f590000-322f594000 rw-p 00000000 00:00 0
322fa00000-322fa02000 r-xp 00000000 fd:00 545709 /lib64/libdl-2.12.so
322fa02000-322fc02000 ---p 00002000 fd:00 545709 /lib64/libdl-2.12.so
322fc02000-322fc03000 r--p 00002000 fd:00 545709 /lib64/libdl-2.12.so
322fc03000-322fc04000 rw-p 00003000 fd:00 545709 /lib64/libdl-2.12.so
3230600000-3230683000 r-xp 00000000 fd:00 545684 /lib64/libm-2.12.so
3230683000-3230882000 ---p 00083000 fd:00 545684 /lib64/libm-2.12.so
3230882000-3230883000 r--p 00082000 fd:00 545684 /lib64/libm-2.12.so
3230883000-3230884000 rw-p 00083000 fd:00 545684 /lib64/libm-2.12.so
7fa70c000000-7fa70c021000 rw-p 00000000 00:00 0
7fa70c021000-7fa710000000 ---p 00000000 00:00 0
7fa7102e7000-7fa7102e9000 r-xp 00000000 fd:00 1320668 /tmp/Install/MyLibraryTest/lib/libMyLibrary.so
7fa7102e9000-7fa7104e8000 ---p 00002000 fd:00 1320668 /tmp/Install/MyLibraryTest/lib/libMyLibrary.so
7fa7104e8000-7fa7104e9000 rw-p 00001000 fd:00 1320668 /tmp/Install/MyLibraryTest/lib/libMyLibrary.so
7fa7104e9000-7fa7104ed000 rw-p 00000000 00:00 0
7fa7104ed000-7fa710503000 r-xp 00000000 fd:00 708322 /usr/local/lib64/libgcc_s.so.1
7fa710503000-7fa710702000 ---p 00016000 fd:00 708322 /usr/local/lib64/libgcc_s.so.1
7fa710702000-7fa710703000 rw-p 00015000 fd:00 708322 /usr/local/lib64/libgcc_s.so.1
7fa710703000-7fa710704000 rw-p 00000000 00:00 0
7fa710704000-7fa710883000 r-xp 00000000 fd:00 708539 /usr/local/lib64/libstdc++.so.6.0.21
7fa710883000-7fa710a83000 ---p 0017f000 fd:00 708539 /usr/local/lib64/libstdc++.so.6.0.21
7fa710a83000-7fa710a8d000 r--p 0017f000 fd:00 708539 /usr/local/lib64/libstdc++.so.6.0.21
7fa710a8d000-7fa710a8f000 rw-p 00189000 fd:00 708539 /usr/local/lib64/libstdc++.so.6.0.21
7fa710a8f000-7fa710a94000 rw-p 00000000 00:00 0
7fa710aa8000-7fa710aaa000 rw-p 00000000 00:00 0
7fa710aaa000-7fa710aac000 r-xp 00000000 fd:00 1325633 /tmp/Build/MyLibraryTest/Release/bin/libMyLibrary.so
7fa710aac000-7fa710cab000 ---p 00002000 fd:00 1325633 /tmp/Build/MyLibraryTest/Release/bin/libMyLibrary.so
7fa710cab000-7fa710cac000 rw-p 00001000 fd:00 1325633 /tmp/Build/MyLibraryTest/Release/bin/libMyLibrary.so
7fa710cac000-7fa710cad000 rw-p 00000000 00:00 0
7fff2fc61000-7fff2fc76000 rw-p 00000000 00:00 0 [stack]
7fff2fde5000-7fff2fde6000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
./test_dyn_libs.sh: line 21: 30880 Abandon (core dumped) ${BuildDir}/MyLibraryTest ${InstallDir}/lib/libMyLibrary.so
--- End of tests
任何帮助都将非常感谢!!!
答案 0 :(得分:3)
正如Todd Fleming评论的那样,我认为在编译测试可执行文件时,您可能错误地将MyLibrary.so链接到了测试可执行文件中。
您可以使用 ldd 检查您的可执行文件是否已链接到库。
我已经在我的ubuntu linux上尝试了完全相同的编译选项。对于测试可执行文件,MyLibrary.so不应该链接,所以我没有链接它。事实证明,奇怪的行为没有发生。 当我将测试可执行文件与MyLibrary.so链接时,结果正是您所说的(包括glibc转储)。这并不太令人惊讶,因为当您将库安装到另一个路径时,加载器会将其视为另一个完全不相关的库,因此会加载。
PS:让我感到惊讶的是,这两个单身人士被安置在同一个记忆位置,这有点令人难以置信。我还在我的mac os x上测试了它(可执行文件链接到库的情况),事实证明在os x上,这两个实例具有不同的内存位置。这对我来说更合理。<强>更新强>
关于为什么这两个实例具有相同的内存位置,实际上它是Linux中符号解析的一个特性。有关详细信息,请参阅注释。谢谢你。指出。
答案 1 :(得分:0)
我认为如果在静态getter中隐藏静态变量,静态初始化问题就解决了。所以在标题中你替换了静态类变量
static MyClass myStaticObjOfMyClass;
使用静态类函数
static MyClass& getInstance();
并在cpp:
中实现它static MyClass& getInstance()
{
static MyClass instance("myStaticObjOfMyClass", true);
return instance;
}
第一次调用getInstance()
时初始化静态对象。
答案 2 :(得分:0)
谢谢大家的回答。 正如托德所说,我忘了为MyLibraryTest包含链接命令。这是:
/usr/local/bin/g++ -O3 -DNDEBUG -rdynamic CMakeFiles/MyLibraryTest.dir/MyLibraryTest.cpp.o -o ../bin/MyLibraryTest -Wl,-rpath,/tmp/Build/MyLibraryTest/Release/bin: ../bin/libMyLibrary.so -ldl
问题与RPATH有关。如果我不再使用-Wl,-rpath选项,那么测试工作正常!
我使用CMake构建我的项目,并发现: https://cmake.org/Wiki/CMake_RPATH_handling。现在我在我的CMakeLists.txt中使用以下命令,它删除-Wl,-rpath链接选项。
set (CMAKE_SKIP_RPATH ON)