Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mixing libstdc++ versions

Tags:

c++

gcc

c++11

There are 2 software teams developing C++ applications for the same OS (Scientific Linux 6.5):

Team_A uses the OS provided compiler and libraries (GCC 4.4.7, GLIBC_2.12, GLIBCXX_3.4.13), to build its C++98 application and various shared libraries.

Team_B uses a newer GCC version (4.8.3) which has been built from source. It's a native compiler, it links against the OS libc, and uses the OS standard headers, but has its own version of stdc++ (GLIBCXX_3.4.19). Team_B uses this compiler in C++11 mode to build its application (AppB), and deploys libstdc++ and libgcc_s along with it.

Team_A provides services to Team_B in form of a shared library (.so, .hpp): LibA. The API of the library is a set of C++ classes (declaration in the header, implementation in the .so), and the methods take std::string and other stdc++ classes as arguments.

At this point we arrive to the problem: AppB constructs GLIBCXX_3.4.19 C++11 style std::whatever objects and passes them to LibA who interprets them as GLIBCXX_3.4.13 C++98 style objects, and this might not be forward compatible.

Is this a problem? Can it lead to an application crash? Are the std::whatever implementations compatible among versions (same memory layout)? What about c++98 vs C++11?

Some plot twists which make me more confused:

  • AFAICT, when AppB runs there's only one libstdc++ loaded, the newer one. Even if LibA links against the older, it won't be loaded.
  • But symbols in libstdc++ are versioned. So, if LibA explicitly uses an older version of a symbol it will be linked against that. This means 2 different implementations of the same function will be used by AppB and LibA.
  • std::string and containters are template classes, this means part of their implementation end up where it's generated, part of it in libstdc++.so. Even if the newer libstdc++ is loaded, the generated template code in LibA is from the older version.

I would like to understand what's exactly happens in this case, if it is risky, and void problems. Getting the teams on the same development environment is not an option. Removing std:: classes from the API would also be very hard to make.

Any pointers welcome! :)

like image 320
Gyorgy Szekely Avatar asked Jan 10 '15 20:01

Gyorgy Szekely


People also ask

Are GCC and Clang ABI compatible?

clang, modulo bugs, is fully C++ ABI compatible with GCC (they both follow the intervendor Itanium ABI) on unix systems. Make sure you use the same standard library for all components because libstdc++ and libc++ are different implementations with completely different object layouts.

Are C ++ 14 and C ++ 17 ABI compatible?

The two implementations are not link-compatible (they have different mangled names, so can't be linked together) but can co-exist in the same binary (they have different mangled names, so don't conflict if one object uses std::string and the other uses std::__cxx11::string ).

What is ABI in GCC?

These details are defined as the compiler Application Binary Interface, or ABI. From GCC version 3 onwards the GNU C++ compiler uses an industry-standard C++ ABI, the Itanium C++ ABI. The GNU C++ compiler, g++, has a compiler command line option to switch between various different C++ ABIs.


1 Answers

Unlike C, there is no defined ABI for C++. That means ....

  1. The C++ mangling may change wikipedia : name mangling. Note how Alpha name mangling changed.
  2. The structure of a class may be different. There may be different decisions for laying out protected:, private: and public: parts of the structure. The location and meaning of the vtable may be moved between compilers. There may be different pre-defined functions such as the typeinfo in the vtable between the different compiler versions.
  3. The implementation of a structure in the STL may be different between versions of C++ (e.g. string sharing was done in earlier Visual studio implementations, but has been banned in C++11).
  4. In Windows, different runtimes may manage their memory differently (bind to different malloc/free). When passing full objects or pointers, this can result in the incorrect free implementation being called.

What can you do to mitigate these problems?

Source sharing

Instead of providing a compiled library, deliver the services as source code to be compiled on the same environment.

Standardize on libstdc++

The source built compiler, can be re-built with the older stdC++. This would limit the impact of point 3).

Create a facade

There is an interface between the two teams, which needs to speak a common language. This language probably ought to be C.

Team A => C++ facade/stub => C interface => C++ facade/proxy => Team B.

The facade should be built in the environment where it will be used.

like image 89
mksteve Avatar answered Sep 22 '22 18:09

mksteve