Introduction
Recently in one of my program, I have faced a strange problem with static variables in shared libraries. I thought I would submit an article on this topic with my ideas for review. I hope I will get feedback with a convincing solution so that I can update this article later on with a clear summary description of what happens with static variables in shared libraries. At the moment, this is an incomplete article with only problem description and no summary.
Problem
Please see the sample code below. I have a simple application, which loads a shared object.Shared object (Windows users consider this as dll) consist of an exported function. This exported function creates a static object.
#include <stdio.h>
#include <dlfcn.h>
typedef void ( * ptrfunc ) ( void );
int main( int argc , char *argv[] )
{
void * ptrVoid;
fprintf( stderr, "opening shared library\n" );
ptrVoid = dlopen( "libso.so" , RTLD_NOW );
if( ptrVoid )
{
ptrfunc pfn = (ptrfunc) dlsym( ptrVoid , "foo" );
if( pfn )
{
fprintf( stderr, "calling symbol %p\n" , pfn );
pfn();
}
dlclose( ptrVoid );
fprintf( stderr, "leaving main\n" );
}
else
{
fprintf( stderr, "error: %s\n" , dlerror() );
}
return 0;
}
#include <stdio.h>
class CCheck
{
public:
CCheck (){fprintf( stderr, "Constructor %p\n" , this );}
~ CCheck (){fprintf( stderr, "Destructor %p\n" , this );}
};
extern "C" void foo()
{
static CCheck tmp;
}
When I executed the application, I got a strange problem. The moment application terminates, I am getting a segmentation fault. Please see the sequence of operation below.
Execution sequence
1. Opening shared library - Library is loaded. Object not created even though there is a static object as part of one function. Compiler is smart enough to delay the creation.
2. Calling symbol - Exported function is invoked from main.
3. Constructor - Constructor is invoked.
4. Leaving main - Even after unloading the dll, destructor is not called, resulting in segmentation fault.
My conclusion
This is what I expected to happen.
1. Opening shared library - Library is loaded. Object not created even though there is a static object as part of one function. Compiler is smart enough to delay the creation.
2. Calling symbol - Exported function is invoked from main. After the function call destructor should not be called since the function can be invoked later on and the object should retain its previous state.
3. Constructor - Constructor is invoked.
4. Destructor - Destructor also should be invoked along with removal of shared library.
5. Leaving main - Since all the memories are cleaned up, no segmentation fault.
In the actual sequence of execution what happened and what I expected, the only difference is, destructor is not invoked in the case actual invocation along with removal of shared library from memory (dlclose, ReleaseLibrary in the case of dll). This leads to a conclusion that this is a bug in the cygwin gcc compiler (Version I have used is Cygwin GCC 3.4.4).
Please see the code attached. Please send me your ideas so that I reach in an appropriate conclusion.
Summary
TODO - Will add later with expert comments.