I build a shared library “libMyLibrary.so” with a class “MyClass” that contains a static variable of type “MyClass”. Then I build an executable “MyLibraryTest” that I link against “libMyLibrary.so”. The main program uses “dlopen” to load dynamically a “.so” given as an argument.
While building, the library and executable are generated in a directory, say, “buildDir/bin”. Then I install the library into “installDir/lib” and the executable into “installDir/bin” (removing the runtime path from the executable).
When I run “buildDir/MyLibraryTest buildDir/MyLibrary.so” with LD_LIBRARY_PATH=buildDir, everything is fine.
But when I run “buildDir/MyLibraryTest installDir/lib/MyLibrary.so” with LD_LIBRARY_PATH=installDir/lib, a very strange thing occurs : – The static variable’s constructor is called twice (once before dlopen, once during dlopen) – At the end of the execution, the destructor is called twice, and this results into a crash.
Here is my code :
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; } }
Here are the compilation and link commands :
/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
And at last here is what happens in the second case (duplicate initialization of the static variable) :
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
Any help would be greatly appreciated !!!
Advertisement
Answer
Thank you all for your answers. As Todd said, I forgot to include the link command for MyLibraryTest. Here it is :
/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
The problem was related to the RPATH. If I do not use the -Wl,-rpath option any more, the test works fine !
I use CMake to build my projects, and found this : https://cmake.org/Wiki/CMake_RPATH_handling. Now I use the following command in my CMakeLists.txt, which removes the -Wl,-rpath link option.
set (CMAKE_SKIP_RPATH ON)