Using singleton in delayed loaded shared library - c++

I have a static C++ library that defines a singleton class. The static member variable of the singleton is a std::unique_ptr. I also have a shared library that defines a plugin which is delayed-loaded by the main application (using dlopen). Both the main application and the shared library link to the static library and make use of its singleton. All parts are compiled using compiler flags -fPIC and -rdynamic using GCC 7.5.0. The shared library and the executable are not linked at link-time.
At run-time, all components seem to make correct use of the same singleton instance. However, even though the constructor of the singleton class is only called once, its destructor is called twice, resulting in a double delete and therefore a segfault. The destructor seems to be called once for each compilation unit it is used in. If the shared library is linked to the main application at link time, this does not happen.
This issue occurred to me first when trying to use Poco::Logger from the C++ Poco library as the static library.
I looked at the question posed here and tried the example (using GCC 7.5.0) replacing the raw pointer with a std:unique_ptr. This results in the same double delete. The only way I seem to be able to prevent the double delete is to link the main application to the shared library at link-time and remove the direct link of the shared library to the static library. This would ensure only 1 copy of the shared library exists at run time. However, I wonder if that would be a good solution (besides that I don't seem to be able to do that through CMake).
Linking the shared library to the main application does not seem to make sense, since not all plugins will be known at compile time and this would defy the purpose of a plug in.
The following minimal example has been based on the example from bourneli
The static library contains the following files:
/*
* singleton.h
*
* Based on: bourneli
* Adaptation: mojoritty
*/
#ifndef SINGLETON_H_
#define SINGLETON_H_
#include <memory>
class singleton
{
private:
singleton();
static std::unique_ptr<singleton> pInstance;
public:
~singleton();
static singleton& instance();
public:
int num;
};
#endif /* SINGLETON_H_ */
and
/*
* singleton.cpp
*
* Based on: bourneli
* Adaptation: mojoritty
*/
#include "singleton.h"
#include <iostream>
singleton::singleton()
{
std::cout << "Constructed " << this << std::endl;
num = -1;
}
singleton::~singleton()
{
std::cout << "Destroyed" << this << std::endl;
}
static singleton& singleton::instance()
{
if (!pInstance)
{
pInstance.reset(new singleton());
}
return *pInstance;
}
std::unique_ptr<singleton> singleton::pInstance;
The shared library contains the following files:
// plugin.h
#include "singleton.h"
#include <iostream>
extern "C" void hello();
and
// plugin.cpp
#include "plugin.h"
void hello()
{
std::cout << "singleton.num in hello.so : " << singleton::instance().num << std::endl;
++singleton::instance().num;
std::cout << "singleton.num in hello.so after ++ : " << singleton::instance().num << std::endl;
}
Finally, the main application contains the following code:
/* main.cpp
*
* Author: bourneli
* Adaptation: mojoritty
*/
#include <iostream>
#include <dlfcn.h>
#include "singleton.h"
int main() {
using std::cout;
using std::cerr;
using std::endl;
singleton::instance().num = 100; // call singleton
cout << "singleton.num in main : " << singleton::instance().num << endl;// call singleton
// open the library
void* handle = dlopen("./libplugin.so", RTLD_LAZY);
if (!handle) {
cerr << "Cannot open library: " << dlerror() << '\n';
return 1;
}
// load the symbol
typedef void (*hello_t)();
// reset errors
dlerror();
hello_t hello = (hello_t) dlsym(handle, "hello");
const char *dlsym_error = dlerror();
if (dlsym_error) {
cerr << "Cannot load symbol 'hello': " << dlerror() << '\n';
dlclose(handle);
return 1;
}
hello(); // call plugin function hello
cout << "singleton.num in main : " << singleton::instance().num << endl;// call singleton
dlclose(handle);
}
Building and running this application results in the follwing terminal output:
created 0x563018c48e70
singleton.num in main : 100
singleton.num in hello.so : 100
singleton.num in hello.so after ++ : 101
singleton.num in main : 101
destroyed 0x563018c48e70
destroyed 0x563018c48e70
free(): double free detected in tcache 2
Aborted (core dumped)

Related

How to portably load dynamic libraries and run their initialization code?

Using GCC and being on Linux, or probably wherever glibc is available, I can use the dl_open() library function to dynamically load a shared-object/DLL:
void *dlopen(const char *filename, int flags);
... and this also runs all functions which, in the ELF format, are marked with .init; or in the C/C++ code, are marked with __attribute__((constructor)) :
How exactly does __attribute__((constructor)) work?
My question is: How can I do the same in a more portable way? I'm interested in portability both to other compilers and other platforms.
Note: I marked this C++ because that's what I'm using, but obviously a C-ish solution in acceptable - as what I've described above is a C-ish solution.
Initializing when library loaded
Edit: Revisited the question again and I found that I didn't answer the initialization part.
The best answer I found is this one which is still platform dependent. Will update if there is a better one.
For platform specific
In windows it's DllMain but be sure to read the part of Dynamic link library best practice to see what's unsafe to call in DllMain
In linux:
__attribute__ ((constructor))
__attribute__ ((destructor))
Load library portably
Since Boost is available on many platforms, its _dll module might be considered as cross platform. Though compilation for different platforms are required.
Following is the basic example for Boost.Dll by importing a single variable in plugin.
Header
#include <boost/config.hpp>
#include <string>
class BOOST_SYMBOL_VISIBLE my_plugin_api {
public:
virtual std::string name() const = 0;
virtual float calculate(float x, float y) = 0;
virtual ~my_plugin_api() {}
};
Source
#include <boost/config.hpp> // for BOOST_SYMBOL_EXPORT
#include "../tutorial_common/my_plugin_api.hpp"
namespace my_namespace {
class my_plugin_sum : public my_plugin_api {
public:
my_plugin_sum() {
std::cout << "Constructing my_plugin_sum" << std::endl;
}
std::string name() const {
return "sum";
}
float calculate(float x, float y) {
return x + y;
}
~my_plugin_sum() {
std::cout << "Destructing my_plugin_sum ;o)" << std::endl;
}
};
// Exporting `my_namespace::plugin` variable with alias name `plugin`
// (Has the same effect as `BOOST_DLL_ALIAS(my_namespace::plugin, plugin)`)
extern "C" BOOST_SYMBOL_EXPORT my_plugin_sum plugin;
my_plugin_sum plugin;
} // namespace my_namespace
Usage: note that append_decorations is the way for seeking platform specific naming convention.
Eg: libplugin.so on linux or plugin.dll on windows.
#include <boost/dll/import.hpp> // for import_alias
#include <iostream>
#include "../tutorial_common/my_plugin_api.hpp"
namespace dll = boost::dll;
int main(int argc, char* argv[]) {
boost::dll::fs::path lib_path(argv[1]); // argv[1] contains path to directory with our plugin library
boost::shared_ptr<my_plugin_api> plugin; // variable to hold a pointer to plugin variable
std::cout << "Loading the plugin" << std::endl;
plugin = dll::import<my_plugin_api>( // type of imported symbol is located between `<` and `>`
lib_path / "my_plugin_sum", // path to the library and library name
"plugin", // name of the symbol to import
dll::load_mode::append_decorations // makes `libmy_plugin_sum.so` or `my_plugin_sum.dll` from `my_plugin_sum`
);
std::cout << "plugin->calculate(1.5, 1.5) call: " << plugin->calculate(1.5, 1.5) << std::endl;
}
To create an object from plugin, here's the factory example.
First, make a factory method returns boost::shared_ptr<my_plugin_aggregator>.
#include <boost/dll/alias.hpp> // for BOOST_DLL_ALIAS
#include "../tutorial_common/my_plugin_api.hpp"
namespace my_namespace {
class my_plugin_aggregator : public my_plugin_api {
float aggr_;
my_plugin_aggregator() : aggr_(0) {}
public:
std::string name() const {
return "aggregator";
}
float calculate(float x, float y) {
aggr_ += x + y;
return aggr_;
}
// Factory method
static boost::shared_ptr<my_plugin_aggregator> create() {
return boost::shared_ptr<my_plugin_aggregator>(
new my_plugin_aggregator()
);
}
};
BOOST_DLL_ALIAS(
my_namespace::my_plugin_aggregator::create, // <-- this function is exported with...
create_plugin // <-- ...this alias name
)
} // namespace my_namespace
Load creator method and create object.
#include <boost/dll/import.hpp> // for import_alias
#include <boost/function.hpp>
#include <iostream>
#include "../tutorial_common/my_plugin_api.hpp"
namespace dll = boost::dll;
int main(int argc, char* argv[]) {
boost::dll::fs::path shared_library_path(argv[1]); // argv[1] contains path to directory with our plugin library
shared_library_path /= "my_plugin_aggregator";
typedef boost::shared_ptr<my_plugin_api> (pluginapi_create_t)();
boost::function<pluginapi_create_t> creator;
creator = boost::dll::import_alias<pluginapi_create_t>( // type of imported symbol must be explicitly specified
shared_library_path, // path to library
"create_plugin", // symbol to import
dll::load_mode::append_decorations // do append extensions and prefixes
);
boost::shared_ptr<my_plugin_api> plugin = creator();
std::cout << "plugin->calculate(1.5, 1.5) call: " << plugin->calculate(1.5, 1.5) << std::endl;
std::cout << "plugin->calculate(1.5, 1.5) second call: " << plugin->calculate(1.5, 1.5) << std::endl;
std::cout << "Plugin Name: " << plugin->name() << std::endl;
}
Note: When creator is destroyed, dynamic library is unloaded as well. Dereferencing plugin after library unloaded is undefined behavior.

c++ call object method using pointer

I created a shared lib, in which I defined a class Foo. In class Foo, there is a function named sayHi(). My question is once I created a Foo object foo, how can I call sayHi() of it. I put my code here.
mylib.h
#ifndef FUNTEST_MYLIB_H
#define FUNTEST_MYLIB_H
class Foo {
public:
int id = 0;
void sayHi();
};
#endif //FUNTEST_MYLIB_H
mylib.cpp
#include <iostream>
#include "mylib.h"
using namespace std;
void Foo::sayHi()
{
cout << "Implemented by lib" << endl;
cout << "id is: " << id << endl;
}
Foo* create()
{
return new Foo();
}
then I use the following commands compile the shared lib:
g++ -c -std=gnu++11 -fPIC mylib.cpp
g++ -shared -fPIC -o mylib.so mylib.o
At the client side, I write two files:
mylib2.cpp
#include <iostream>
#include "mylib.h"
using namespace std;
void Foo::sayHi() {
cout << "Implemented by caller" << endl;
cout << "id is: " << id << endl;
}
main.cpp
#include <iostream>
#include <dlfcn.h>
#include "mylib.h"
using namespace std;
Foo* (*create)();
void (*sayHi)();
int main() {
void* lib = dlopen("./mylib.so", RTLD_LAZY);
create = (Foo* (*)())dlsym(lib, "_Z6createv");
sayHi = (void (*)())dlsym(lib, "_ZN3Foo5sayHiEv");
Foo* foo = create();
sayHi();
foo->sayHi();
foo->id = 100;
cout << "Set id to " << foo->id << endl;
/*
*
* how can I make the follow statement 'sayHi();'
* output the following content:
* Implemented by lib
* id is: 100
*/
sayHi(); // line 29, FIXME
foo->sayHi();
return 0;
}
compile the client with following command:
g++ -std=gnu++11 main.cpp mylib.h mylib2.cpp -ldl
finally run the client:
./a.out
the output is:
Implemented by lib
id is: 0
Implemented by caller
id is: 0
Set id to 100
Implemented by lib
id is: -1407102376 // FIXME
Implemented by caller
id is: 100
how can I make the statement 'sayHi();' at line 29 output the following content:
Implemented by lib
id is: 100
I know if i call the sayHi() function directly, without the foo object, the output will be wrong. But how can I fix it?
The declaration of the sayHi global variable in main.cpp is wrong. You're declaring it as a function pointer. However, since it points to a member function, it needs to be a member function pointer.
void (Foo::*sayHi)();
Then when you call it you need a Foo object:
(foo->*sayHi)();
Alternatively, if you make the sayHi method virtual, you shouldn't need to load the symbol for it at all, since that will be effectively handled by the vtable.

C++ Static members of a class are initialized after constructor

I have a problem with static members of a class not being initialized before the constructor. Am i doing something wrong? Is it a bug in G++ ?
Any workarounds?
g++ --version : (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4
I am also using Eclipse as my IDE, but i just copy the static lib headers to /usr/include/StaticTestLib/InitTest.h and the library to /usr/lib/x86_64-linux-gnu/libStaticTestLib.a
Note this only happens if the object that holds the data is defined before main and the class is in a Static Library.
Static library header (the static library itself is named StaticTestLib):
InitTest.h
#include <iostream>
namespace StaticTestLib {
class notifier_header{
public:
notifier_header(){
std::cout<<"static var init"<<std::endl;
}
};
class InitTest {
public:
static notifier_header _header_notifier;
InitTest();
virtual ~InitTest();
};
}
Static library source file:
InitTest.cpp
#include "InitTest.h"
namespace StaticTestLib {
notifier_header InitTest::_header_notifier;
class notifier_cpp{
public:
notifier_cpp(){
std::cout<<"code before constructor"<<std::endl;
}
}_notifier_in_cpp;
InitTest::InitTest() {
std::cout<<"constructor"<<std::endl;
}
InitTest::~InitTest() {
std::cout<<"destructor"<<std::endl;
}
}
This program:
StaticTest.cpp
#include <iostream>
#include <StaticTestLib/InitTest.h>
StaticTestLib::InitTest test;
int main() {
std::cout << "program main" << std::endl;
std::cout << "program end" << std::endl;
return 0;
}
… outputs:
constructor
static var init
code before constructor
program main
program end
destructor
But this program:
#include <iostream>
#include <StaticTestLib/InitTest.h>
int main() {
std::cout << "program main" << std::endl;
StaticTestLib::InitTest test;
std::cout << "program end" << std::endl;
return 0;
}
… outputs:
static var init
code before constructor
program main
contructor
program end
destructor
My guess is that this is related to the order of static objects initialisation in different compilation units being undefined.
The second code snippet where you create a test object in your main is easy to explain. Static initialisation will always happen before any code is executed, so by the time you enter main, your notifier_header object is definitely created.
Now, when you create your test before main, you have two static objects. notifier_header object does not depend on your InitTest: it is scoped within that class, but it is stored in static memory. You seem to reference the notifier_header in your InitTest.cpp, which is a different compilation unit to main. A compiler is free to do static allocations in any order for those two units, provided that there is no interdependencies.
If your constructor depended on notifier_header, you could use it as a singleton. Create a function that returns an instance of a static object (headerInstance in the example below), and upon its call, the object will be created:
#include <iostream>
namespace StaticTestLib {
class notifier_header{
public:
notifier_header(){
std::cout<<"static var init"<<std::endl;
}
};
class InitTest {
public:
InitTest();
virtual ~InitTest();
notifier_header& headerInstance();
};
}
Static library source file (InitTest.cpp)
#include "InitTest.h"
namespace StaticTestLib {
class notifier_cpp{
public:
notifier_cpp(){
std::cout<<"code before constructor"<<std::endl;
}
}_notifier_in_cpp;
InitTest::InitTest() {
headerInstance();
std::cout<<"constructor"<<std::endl;
}
InitTest::~InitTest() {
std::cout<<"destructor"<<std::endl;
}
notifier_header& InitTest::headerInstance() {
static notifier_header _header_notifier; // will only be constructed once
return _header_notifier;
}
}
The output I get:
static var init
constructor
code before constructor
program main
program end
destructor

C++ Dynamically load arbitrary function from DLL into std::function

How can I load an arbitrary dynamic-link library (dll) function into a std::function object using a single function?
For example I would like to compile two functions into a dll:
// test.dll
int plusFive(int value) {
return value + 5;
}
void printHello() {
std::cout << "Hello!" << std::endl;
}
And load them both at runtime using a single function like this:
// main.cc
#include <functional>
int main() {
std::function<int(int)> func1(loadDllFunc("test.dll", "plusFive"));
std::function<void()> func2(loadDllFunc("test.dll", "printHello"));
}
Use the WinAPI functions provided in windows.h (descriptions taken from MSDN Dev Center).
LoadLibrary - Loads the specified module into the address space of the calling process. Returns a handle to the module.
GetProcAddress - Retrieves the address of an exported function or variable from the specified dynamic-link library (DLL). Returns the address of the exported function or variable.
Use this function to load a specific function and return a std::function object:
// main.cc
#include <iostream>
#include <string>
#include <functional>
#include <windows.h>
template <typename T>
std::function<T> loadDllFunc(const std::string& dllName, const std::string& funcName) {
// Load DLL.
HINSTANCE hGetProcIDDLL = LoadLibrary(dllName.c_str());
// Check if DLL is loaded.
if (hGetProcIDDLL == NULL) {
std::cerr << "Could not load DLL \"" << dllName << "\"" << std::endl;
exit(EXIT_FAILURE);
}
// Locate function in DLL.
FARPROC lpfnGetProcessID = GetProcAddress(hGetProcIDDLL, funcName.c_str());
// Check if function was located.
if (!lpfnGetProcessID) {
std::cerr << "Could not locate the function \"" << funcName << "\" in DLL\"" << dllName << "\"" << std::endl;
exit(EXIT_FAILURE);
}
// Create function object from function pointer.
std::function<T> func(reinterpret_cast<__stdcall T*>(lpfnGetProcessID));
return func;
}
The DLL source should be written like this:
// test.cc (test.dll)
#include <iostream>
// Declare function prototypes with "extern C" to prevent name mangling.
// Declare functions using __declspec(dllexport) to signify the intent to export.
extern "C" {
__declspec(dllexport) int __stdcall plusFive(int);
__declspec(dllexport) void __stdcall printHello();
}
int plusFive(int value) {
return value + 5;
}
void printHello() {
std::cout << "Hello!" << std::endl;
}
And then use loadDllFunc like this:
// main.cc
int main() {
auto func1 = loadDllFunc<int(int)>("test.dll", "plusFive");
auto func2 = loadDllFunc<void()>("test.dll", "printHello");
std::cout << "Result of func1: " << func1(1) << std::endl;
func2();
}
Output:
Result of func1: 6
Hello!
As a sidenote the DLL can be compiled using GCC (4.7.2) like this:
g++ -shared -o test.dll test.cc -std=c++11
Edit:
I'm not sure that the cast in loadDllFunc gives the correct type:
std::function<T> func(reinterpret_cast<__stdcall T*>(lpfnGetProcessID));
It seems to cast it to __stdcall int (*)(int) when it should be int (__stdcall *)(int).
Here is another way to implement loadDllFunc using an auxiliary parser class. This solution will correctly cast the function pointer to int (__stdcall *)(int).
template <typename T>
struct TypeParser {};
template <typename Ret, typename... Args>
struct TypeParser<Ret(Args...)> {
static std::function<Ret(Args...)> createFunction(const FARPROC lpfnGetProcessID) {
return std::function<Ret(Args...)>(reinterpret_cast<Ret (__stdcall *)(Args...)>(lpfnGetProcessID));
}
};
template <typename T>
std::function<T> loadDllFunc(const std::string& dllName, const std::string& funcName) {
// Load DLL.
HINSTANCE hGetProcIDDLL = LoadLibrary(dllName.c_str());
// Check if DLL is loaded.
if (hGetProcIDDLL == NULL) {
std::cerr << "Could not load DLL \"" << dllName << "\"" << std::endl;
exit(EXIT_FAILURE);
}
// Locate function in DLL.
FARPROC lpfnGetProcessID = GetProcAddress(hGetProcIDDLL, funcName.c_str());
// Check if function was located.
if (!lpfnGetProcessID) {
std::cerr << "Could not locate the function \"" << funcName << "\" in DLL\"" << dllName << "\"" << std::endl;
exit(EXIT_FAILURE);
}
// Create function object from function pointer.
return TypeParser<T>::createFunction(lpfnGetProcessID);
}

Explicit instantiation of a templated class and dynamic_cast in a shared library

I stumbled into a problem today that I can't seem to solve. I am compiling a shared library that includes a templated class (Derived<T>, whose base is Base) and some explicit instantiations of this class. I would like the library user to extend from this templated class. The problem arises when I try to dynamic_cast the user's instance from Base* to Derived<T>*.
I have narrowed down the problem to this MWE:
The shared library contains the following files:
Base.h
#ifndef BASE_H_
#define BASE_H_
class Base {
public:
Base();
virtual ~Base();
};
#endif /* BASE_H_ */
Derived.h
#ifndef DERIVED_H_
#define DERIVED_H_
#include <Base.h>
template <typename T>
class Derived : public Base {
public:
Derived();
virtual ~Derived();
};
#endif /* DERIVED_H_ */
Derived.cpp
#include <Derived.h>
template <typename T>
Derived<T>::Derived() :
Base() {
}
template <typename T>
Derived<T>::~Derived() {
}
// explicit instantiations
template class Derived<float>;
template class Derived<double>;
template class Derived<long double>;
Helper.h
#ifndef HELPER_H_
#define HELPER_H_
#include <Base.h>
class Helper {
public:
Helper(Base* m);
virtual ~Helper();
};
#endif /* HELPER_H_ */
Helper.cpp
#include <Helper.h>
#include <Base.h>
#include <Derived.h>
#include <iostream>
using namespace std;
Helper::Helper(Base* m) {
cout << "after received " << m << endl;
cout << "after fom: " << dynamic_cast< Derived<float>* >(m) << endl;
cout << "after dom: " << dynamic_cast< Derived<double>* >(m) << endl;
cout << "after ldom: " << dynamic_cast< Derived<long double>* >(m) << endl;
cout << "===" << endl;
}
Helper::~Helper() {
}
And a simple code that uses the library could be:
test.cpp
#include <Derived.h>
#include <Helper.h>
#include <iostream>
using namespace std;
class MyModel : public Derived<double> {
public:
MyModel() : Derived<double>() {
};
virtual ~MyModel() {
};
};
int main(int argc, char *argv[]) {
MyModel om1;
cout << "created mymodel " << &om1 << endl;
cout << "before fom: " << dynamic_cast< Derived<float>* >(&om1) << endl;
cout << "before dom: " << dynamic_cast< Derived<double>* >(&om1) << endl;
cout << "before ldom: " << dynamic_cast< Derived<long double>* >(&om1) << endl;
cout << "===" << endl;
Helper root(&om1);
return 0;
}
The problem is that when I create a shared library and link test.cpp against it, the dynamic_cast fails. Here's an example output:
created mymodel 0x7fff5fbff3e0
before fom: 0
before dom: 0x7fff5fbff3e0
before ldom: 0
===
after received 0x7fff5fbff3e0
after fom: 0
after dom: 0 // <<< Here I expected it to succeed and return a non-null pointer
after ldom: 0
===
However, if I compile the whole library and example together, the cast succeeds:
created mymodel 0x7fff5fbff3e0
before fom: 0
before dom: 0x7fff5fbff3e0
before ldom: 0
===
after received 0x7fff5fbff3e0
after fom: 0
after dom: 0x7fff5fbff3e0
after ldom: 0
===
My question is : Why is the dynamic_cast failing?
And, under the premise that I would like to maintain a class structure like the example, and continue to use a shared library: how can I successfully obtain the Derived<some type>* cast from a Base* ?
I assume you are on Linux/GCC, because on Windows it should "just work".
It does not "just work" with GCC, because for performance RTTI support in GCC relies on pointer comparison. It is all explained in this GCC FAQ, including how it can be resolved. EDIT: though, this FAQ says that it does not work with dlopen() while explicit linking with a shared library should work; so maybe there is something else, such as the bug mentioned below.
Some other links I found that can be of help:
dynamic_cast an interface from a shared library which was loaded by lt_dlopen(libtool) doesn't work
dynamic cast with interfaces
C++ dynamic_cast bug in Mac OS 10.6 Snow Leopard
There is no surprise here. Even for normal non-templated classes, you should never expect the RTTI to work across shared-library boundaries. For some compilers, on some OSes, with some compiler or linker options, it might work, but in general, it will not, and is not required to (explicitly left unspecified in the Standard). And even if you make it work, it will be unsustainable in the long-run.
In my experience, the cases when the RTTI cannot cross-over between shared-library boundaries far outweigh the cases when it can.
The solution is to either:
Restrict all the constructions of objects from these derived types to within the shared-library code where the dynamic_cast is used (this solution is pretty hard to manage).
Do not use dynamic_cast at all (this solution is idealistic, seldom applicable).
Do not use shared-libraries (evaluate if shared-libraries are really what you need, or maybe, expose a higher-level interface from your shared-library, that doesn't expose polymorphic types to be derived (which seem to suggest that an "open-architecture" is more appropriate in your application)).
Define your own RTTI system and casting operator (this could be hard, depending on your skill, but it doesn't amount to much code, and many main-stream projects use this solution and you can find plenty of examples on how to do this).