Kirby Zhou
Kirby Zhou

Reputation: 181

Undocumented ABI changes of std::function between GCC-4 and GCC-5/6/7/8/9, how to make a .so working with devtoolset-4/6/7/8/9?

with _GLIBCXX_USE_CXX11_ABI=0 std::function of GCC-4 is different of GCC-5 and follwing versions.

The following code show you the fact:

==> lib.cc <==

#include <functional>

std::function<int(const void*p)> holder;

int run_holder(const void *p)
{
    return holder(p);
}

==> main.cc <==

#include <stdio.h>
#include <functional>

extern int run_holder(const void*p);
extern std::function<int(const void*p)> holder;

int foo(const void* p)
{
    printf("p=%p\n", p);
    return 0;
}

int main()
{
    holder = foo;
    foo((void*)0x12345678);
    holder((void*)0x12345678);
    run_holder((void*)0x12345678);
}

==> make.sh <==

#!/bin/bash
GCC4=/usr/bin/g++
GCCN="scl enable devtoolset-5 -- g++"

$GCC4 -std=c++11 -c -g lib.cc -shared -o libfoo.so &&
$GCCN -std=c++11 -L. -lfoo -g main.cc -o a.out &&
LD_LIBRARY_PATH=. ./a.out

expected result, something like:

p=0x12345678
p=0x12345678
p=0x12345678

actual result:

p=0x12345678
./make.sh: line 6:   973 Segmentation fault      LD_LIBRARY_PATH=. ./a.out

The reason is the implementation of std::function changes without document.

gcc4: /usr/include/c++/4.8.2/functional:2430

typedef _Res (*_Invoker_type)(const _Any_data&, _ArgTypes...);

gcc5: /opt/rh/devtoolset-4/root/usr/include/c++/5.3.1/functional:2226 gcc8: /opt/rh/devtoolset-8/root/usr/include/c++/8/bits/std_function.h:609

using _Invoker_type = _Res (*)(const _Any_data&, _ArgTypes&&...);

So I can not write a .so using std::function compiled by gcc4 and used by gcc5/6/7/8. There is no macro like _GLIBCXX_USE_CXX11_ABI can control the behavior.

Upvotes: 0

Views: 622

Answers (1)

Jonathan Wakely
Jonathan Wakely

Reputation: 171333

So I can not write a .so using std::function compiled by gcc4 and used by gcc5/6/7/8.

Correct. Neither Red Hat nor the GCC project has ever claimed that's possible, quite the opposite. C++11 support in GCC 4.x was incomplete and unstable, and subject to ABI changes and API changes. What you're trying to do was never supported.

I've explained this in more detail at https://stackoverflow.com/a/49119902/981959

The Developer Toolset documentation covers it too (emphasis mine):

"A compiler in C++11 or C++14 mode is only guaranteed to be compatible with another compiler in C++11 or C++14 mode if they are from the same release series (for example from Red Hat Developer Toolset 6.x).
...
"Using the C++14 language version is supported in Red Hat Developer Toolset when all C++ objects compiled with the respective flag have been built using Red Hat Developer Toolset 6 or later. Objects compiled by the system GCC in its default mode of C++98 are also compatible, but objects compiled with the system GCC in C++11 or C++14 mode are not compatible."

There is no macro like _GLIBCXX_USE_CXX11_ABI can control the behavior.

We do not provide macros to control things that are unsupported and cannot work.

If you want to use C++11 with a mix of GCC versions you need to use a release that has stable, non-experimental support for C++11. So not GCC 4.x.

Upvotes: 2

Related Questions