As far as I understand namespace scope static variables should have one copy in each compilation unit. So if I have a header file like this:
class BadLad {
public:
BadLad();
~BadLad();
};
static std::unique_ptr<int> sCount;
static BadLad sBadLad;
and badlad.cpp
#include "badlad.h"
BadLad::BadLad() {
if (!sCount) {
sCount.reset(new int(1));
std::cout<<"BadLad, reset count, "<<*sCount<<std::endl;
}
else {
++*sCount;
std::cout<<"BadLad, "<<*sCount<<std::endl;
}
}
BadLad::~BadLad() {
if (sCount && --*sCount == 0) {
std::cout<<"~BadLad, delete "<<*sCount<<std::endl;
delete(sCount.release());
}
else {
std::cout<<"~BadLad, "<<*sCount<<std::endl;
}
}
I expect sCount and sBadLad to be unique in each cpp file that includes badlad.h.
However, I found it's not the case in the following experiment:
- I compile badlad to a shared library
libBadLad.so
. - I create another shared library
libPlugin.so
which linkslibBadLad.so
, only plugin.cpp includesbadlad.h
, so I expect there is one copy ofsCount
in libPlugin.so. - I create a main program that links libBadLad.so, I expect there is
one copy of
sCount
in main.
The main program looks like this:
#include <dlfcn.h>
int main() {
void* dll1 = dlopen("./libplugin.so", RTLD_LAZY);
dlclose(dll1);
void* dll2 = dlopen("./libplugin.so", RTLD_LAZY);
dlclose(dll2);
return 0;
}
When executing the main program, I can see the sCount
variable is first created and set to 1 before main is called, which is expected. But then after the first dlopen
is called, sCount
is incremented to 2, and subsequently decreased to 1 when dlclose
is called. The same happens to the second dlopen/dlclose.
So my questions is, why there is only one copy of sCount? Why the linker doesn't keep the copies separate (which I think is what most people expect)? It behaves the same if I link libPlugin.so to main directly instead of dlopen.
I'm running this on macOS with clang-4 (clang-900.0.39.2).
EDIT: please see the full source code in this repo.