I'm making a simple plugin framework in which I'd like to be able to dlopen() a shared library (i.e. plugin), inspect and use whatever factory functions is provides and eventually dlclose() it, leaving no trace.
My factory system is trivial, with a single exported function that returns a pointer to a common Base class. To check the plugin has been unloaded properly, I have a static object whose destructor sets a bool from the main program.
Here's the main program:
// 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;
}
And the plugin's code is:
// 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; }
If executed, the output is:
false
false
~Finilizer()
This shows the call to dlclose() doesn't work as expected and the library was not unloaded until the program's exit.
However, if we move the vector to outside the function, so the last 8 lines read:
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; }
Then dlclose() works properly and the output is:
false
~Finilizer()
true
The same results are generated if the vector is left in the function but no factory is exported:
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; }
Positive results are found if the vector is substituted with a C array:
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; }
Is this a bug in GCC/Linux? Is there any workaround so that complex objects may be static-declared in an factorified class's member function?
See Question&Answers more detail:
os