Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory still reachable bug fixed, but why?

I'm experimenting with shared libraries to build a modularized program.

There are two cpp files to compile:

Shared library, compile with

g++ -fPIC -shared module.cpp -o module.so

//module.cpp
#include <iostream>

File using the shared library, compile with

g++ src/main.cpp -ldl -o binary

or

g++ -DFIX src/main.cpp -ldl -o binary

//main.cpp
#include <dlfcn.h>
#ifdef FIX
# include <iostream>
#endif

int main()
{
   void* h = dlopen("./module.so", RTLD_LAZY);
   if ( h )
   {
      dlclose(h);
   }
}

With FIX undefined, valgrind reports lot's of still reachable memory (5,373bytes), with FIX defined, no memory is leaked.

What's the problem with using iostream in shared libraries?

This problem occurs with g++-4.6, g++-4.7 and g++-4.8. g++-4.4 does not show this behaviour. I don't have other compilers to test with, sadly (and I don't want to switch to g++-4.4 because of this).

Update:

Compiling the shared library file with the additional flags -static-libstdc++ -static-libgcc reduces the number of leaked blocks, but not completely. -static-libgcc alone has no effect, -static-libstdc++ has some effect, but not as much as both.

like image 770
stefan Avatar asked Oct 04 '13 16:10

stefan


1 Answers

1. Why or how does this code snippet "fix" the issue?

I'm not sure why without digging into the libstdc++ code, but I assume that the memory allocated by the iostreams library, which is kept allocated for the duration of the whole program, is reported as a problem by valgrind when it is allocated in a shared library, but not when allocated in the main program.

2. What equivalent, independent (from the standard library) code snippet provides the same bug fix?

Firstly, I don't know why you want something "independent from the standard library" when the still reachable memory is probably being allocated by the standard library. The fix is either don't use the standard library at all, anywhere, or use it differently.

Secondly, that "fix" is undefined behaviour, because you violate the One Definition Rule by redefining std::ios_base differently to the proper definition in the std lib.

The correct way to get the same behaviour is to #include <iostream> in your main.cpp file, including <iostream> defines a static std::ios_base::Init object. Alternatively, just #include <ios> and then define the static variable (but don't redefine the std::ios_base type) but that's basically what <iostream> does, so you might as well use that.

like image 179
Jonathan Wakely Avatar answered Oct 15 '22 09:10

Jonathan Wakely