[First presented on gcc-help. Submitted as per the suggestion of Ian Lance Taylor, see http://gcc.gnu.org/ml/gcc-help/2011-03/msg00340.html ] Consider the following shared object: // g++ -o libtest.so -shared -fPIC dltestlib.cpp #include <iostream> int global_f() { static int i=0; return i; } struct C { int class_scope_f() { static int i=0; return i; } C() { global_f(); // class_scope_f(); // CULPRIT } ~C() { std::cout << "Destructor called" << std::endl; } }; static C c; Also consider the following test program, which merely loads and unloads this library using dlopen/dlclose. // g++ dltest2.cpp -ldl #include <dlfcn.h> #include <iostream> int main(int argc, const char* argv[]) { if (argc!=2) return -1; const char* fname = argv[1]; std::cout << "Opening: " << fname << std::endl; void* handle = dlopen( fname, RTLD_NOW | RTLD_LOCAL); std::cout << "Handle after dlopen: " << handle << std::endl; if(!handle) { std::cout << dlerror() << std::endl; } dlclose(handle); // do not load. Only check if the file is resident. handle = dlopen( fname, RTLD_NOW | RTLD_NOLOAD); std::cout << "Handle after dlclose: " << handle << std::endl; std::cout << "Exiting..." << std::endl; } Providing the abovementioned library as argument, I get the expected result: ./a.out /home/jan/src/gum-cvs/ideas/jan/libtest.so Opening: /home/jan/src/gum-cvs/ideas/jan/libtest.so Handle after dlopen: 0x602050 Destructor called Handle after dlclose: 0 Exiting... In particular, the library *is* unloaded by dlclose (so the global destructor of object c in the library is called before the program is exiting.) And now for the problem... If I comment in line 11 of the library module (marked CULPRIT), thus calling class_scope_f(), and try again, the result is: Opening: /home/jan/src/gum-cvs/ideas/jan/libtest.so Handle after dlopen: 0x602050 Handle after dlclose: 0x602050 Exiting... Destructor called Now the library unloading fails (the handle is still !=0, and indeed the destructor of c is not called before the program terminates). I assume this is because there is a difference in lifetime between local static variables in functions in global scope vs. those of member functions. Is this the intended behaviour? (I say 'intended', not 'mandated', because I know so's are beyond the scope of ISO-C++.) If not, should I file a report? I am on OpenSuSE 11.4; that is: glibc 2.11.3, gcc 4.5.1, binutils 2.21.
+ .type _ZZN1C13class_scope_fEvE1i, @gnu_unique_object - .type _ZZN1C13class_scope_fEvE1i, @object - works but + does not. 4.4 produces object while 4.5 and above produce @gnu_unique_object.
http://gcc.gnu.org/ml/gcc-patches/2009-07/msg01240.html was the patch which changed to use @gnu_unique_object . Jason can you explain why this is causing an issue where the function passed to __cxa_atexit being called?
It has nothing to do with __cxa_atexit. The dynamic linker sets if (map->l_type == lt_loaded) /* Make sure we don't unload this object by setting the appropriate flag. */ map->l_flags_1 |= DF_1_NODELETE; whenever doing successful symbol lookup of a STB_GNU_UNIQUE symbol, so that that symbol will always be found at that point afterwards.
(In reply to comment #3) Sorry for being pedantic, but would you care to explain how your observation renders this report invalid? I am afraid I do not understand this resolution. Do you assert that the two cases (static local in global vs. class scope function) are deliberately treated differently? If so, is this an implementation choice, or is it based on a document that I should have read (which one)? If this isn't changed back, shouldn't this change at least be documented? It may break more user code, not just mine... Thanks again for your time.
(In reply to comment #4) > (In reply to comment #3) > Sorry for being pedantic, but would you care to explain how your observation > renders this report invalid? I am afraid I do not understand this resolution. > > Do you assert that the two cases (static local in global vs. class scope > function) are deliberately treated differently? If so, is this an > implementation choice, or is it based on a document that I should have read > (which one)? Yes they are different because C::class_scope_f is a vague linkage while global_f is global linkage. So the i in each one is of different linkage. If you want C type to be local to the shared, then you need to use either the hidden attribute on it or use -fvisibility=hidden.