This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Shared object compiled with g++ is not unloaded


Hi all!

I've faced with strange behavior when I investigated a bug on a rather
new distros of Linux. I'm not sure that it is a bug of gcc, but may be
someone can bring some light to it.

So, my project heavily uses plugins which are dynamically loaded with
dlopen() and unloaded with dlclose() functions. I've got report that
some (not all) plugins are not unloaded: they remain in the process
map and if you put a new version of binary it's not loaded until
program is finished and started again. This happens only on rather new
distros: RHEL 7x (gcc 4.8), Debian 7 (gcc 4.7) and last versions of
Ubuntu (gcc 4.7 - 4.9). While on RHEL 6.x and Debian 6.x (gcc 4.4 on
both) everything works as expected. Checked only on x86_64
architecture.

So I "bisected" the code to find why this happens. I've found that if
plugin contains a static variable in the inlined function, then
dlclose() leaves the SO in the memory. Also I've found that it happens
only if it is compiled with g++. The same example renamed to *.c and
compiled with gcc works OK.

Attached is the sample which reproduces this effect. Use make command
to build 'test' executable and 'test.so' shared object, then run:
$ ./test

If it outputs something like:
7fc80cdf2000-7fc80cdf3000 r-xp 00000000 fe:02 5902461
  /home/tests/so/test.so
7fc80cdf3000-7fc80cff2000 ---p 00001000 fe:02 5902461
  /home/tests/so/test.so
7fc80cff2000-7fc80cff3000 rw-p 00000000 fe:02 5902461
  /home/tests/so/test.so

then shared object was not unloaded. Remove "inline" keyword in so.cpp
and everything works fine.

That bad thing is that some parts of boost also make the plugin
unloadable and this can be controlled.

So, is it a bug? If no, can it be somehow workarounded?
--
With best regards
  Max Dmitrichenko
#include <dlfcn.h>

#include <iostream>
#include <fstream>
#include <string>

int main()
{
    void* handle = dlopen("test.so", RTLD_NOW);
    if(!handle)
    {
        std::cerr << "Failed to load shared object: " << dlerror() << std::endl;
        return 1;
    }

    int rc = dlclose(handle);
    if(rc)
    {
        std::cerr << "Failed to unload shared object: " << dlerror() << std::endl;
        return 1;
    }

    std::ifstream map("/proc/self/maps");
    while(!map.eof())
    {
        std::string line;
        std::getline(map, line);
        if(line.find("test.so") != std::string::npos)
        {
            std::cout << line << std::endl;
        }
    }

    return 0;
}

Attachment: Makefile
Description: Binary data

inline
int b()
{
    static int x = 0;
    return x;
}

int a()
{
    return b();
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]