Has dlopen() behaviour changed between libc 4.1 and libc 4.4?
David Aldrich
David.Aldrich@EMEA.NEC.COM
Mon May 13 14:34:00 GMT 2013
Hi
We develop and maintain a fairly large C application which we build with the gcc 4.1 compiler suite and run under Centos 5. That is obviously a fairly old toolset set so we have been working on making the application compatible with gcc 4.4. This work program is almost complete but we have one problem that we are unable to fix. This problem is associated with the dlopen() function.
Our application executes simulations based on user-defined parameter files. There are various simulation models that can be run and we have separated the code for each model into a separate dynamic library. The parameter file specifies which models are required for a simulation and, therefore, which dynamic libraries the core program ('kernel') must load before running the simulation.
The dynamic libraries have inter-dependencies, so they must be loaded in a certain order. We can't rely on the user to understand those dependencies so we load the libraries iteratively, keeping a record of which ones failed to load, until all libraries have loaded successfully.
Here is the algorithm:
vector <string> notYetLoaded = a_LibFileNames; // Load vector with full path of each library
bool failed = false;
std::vector<void*> m_dynamicLibHandles;
while (notYetLoaded.size()>0 && !failed) {
vector <string> temp;
for (unsigned i=0; i<notYetLoaded.size(); i++)
{
void* testHandle = dlopen(notYetLoaded[ind].c_str(),RTLD_NOW | RTLD_GLOBAL | RTLD_NOLOAD);
if (testHandle==NULL)
{
// Library not resident so load it
void* handle = dlopen(notYetLoaded[ind].c_str(),RTLD_NOW | RTLD_GLOBAL);
if (handle!=NULL)
// Load succeeded - store handle
dynamicLibHandles.push_back(handle);
else
// Load failed - try again next time
temp.push_back(notYetLoaded[ind]);
}
}
if ( notYetLoaded.size()==temp.size() )
{
// Trying another pass won't help
failed = true;
}
else
{
// This is the list for the next attempt
notYetLoaded = temp;
}
}
Now, this code runs fine when built with gcc 4.1 on Centos 5. We always succeed in loading all required libraries after a few passes through the while loop. But when we build and run it with gcc 4.4.7 on Centos 6, a certain library always fails to load. This is repeatable. Here's the behaviour:
If our list contains libA, libB, libC, libD, libE, the trace output shows:
PASS 1
Attempting to load file libA
Loading libA
Attempting to load file libB
Failed to load libB
Attempting to load file libC
Loading libC
Attempting to load file libD
Failed to load libD
Attempting to load file libE
Failed to load libE
PASS 2
Attempting to load file libB
Loading libB
Attempting to load file libD
< dlopen( ..., RTLD_NOLOAD) returns a handle - i.e. it thinks library D is already loaded, so we don't try to load it >
Attempting to load file libE Loading libC
So the code thinks that all the libraries loaded, but actually libD never got loaded. On the first pass LibD failed to load, but on the second pass the code believes the libD is already loaded and doesn't try to load it again.
It is odd that this changed behaviour is associated with moving from gcc 4.1 to gcc 4.4. I am told that this behaviour change is more likely to be associated with libc than with gcc, so I posted to this list.
Please can anyone suggest a fix for this problem?
Best regards
David
More information about the Libc-help
mailing list