g++-8 in disco is broken with libstdc++6 from gcc9 and libstdc++fs

Bug #1824721 reported by Roger Leigh on 2019-04-14
20
This bug affects 4 people
Affects Status Importance Assigned to Milestone
gcc
Invalid
Medium
gcc-8 (Ubuntu)
Undecided
Unassigned

Bug Description

There is a significant incompatibility here which leaves the default C++ compiler broken with C++17 std::filesystem usage. Unfortunately, there isn't an obvious workaround since there's only one libstdc++6 package, and it's using the non-default and unreleased GCC9 version of libstdc++, making it impossible to use the compatible GCC8 version of the library.

% cat testpath.cpp
#include <filesystem>

int main()
{
  std::filesystem::path p("test");
}

g++-9 -std=c++17 -lstdc++fs -g3 -o testpath testpath.cpp
% ./testpath

% g++-8 -std=c++17 -lstdc++fs -g3 -o testpath testpath.cpp
% ./testpath
zsh: segmentation fault (core dumped) ./testpath

% gdb testpath
GNU gdb (Ubuntu 8.2.91.20190405-0ubuntu3) 8.2.91.20190405-git
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from testpath...
(gdb) run
Starting program: /tmp/testpath

Program received signal SIGSEGV, Segmentation fault.
0x000055555555649b in std::vector<std::filesystem::__cxx11::path::_Cmpt, std::allocator<std::filesystem::__cxx11::path::_Cmpt> >::~vector (this=0x23, __in_chrg=<optimised out>) at /usr/include/c++/8/bits/stl_vector.h:567
567 std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
(gdb) bt
#0 0x000055555555649b in std::vector<std::filesystem::__cxx11::path::_Cmpt, std::allocator<std::filesystem::__cxx11::path::_Cmpt> >::~vector (this=0x23, __in_chrg=<optimised out>) at /usr/include/c++/8/bits/stl_vector.h:567
#1 0x0000555555556314 in std::filesystem::__cxx11::path::~path (this=0x3, __in_chrg=<optimised out>)
    at /usr/include/c++/8/bits/fs_path.h:208
#2 0x0000555555556f5c in std::filesystem::__cxx11::path::_Cmpt::~_Cmpt (this=0x3, __in_chrg=<optimised out>)
    at /usr/include/c++/8/bits/fs_path.h:643
#3 0x0000555555556f77 in std::_Destroy<std::filesystem::__cxx11::path::_Cmpt> (__pointer=0x3)
    at /usr/include/c++/8/bits/stl_construct.h:98
#4 0x0000555555556e27 in std::_Destroy_aux<false>::__destroy<std::filesystem::__cxx11::path::_Cmpt*> (
    __first=0x3, __last=0x0) at /usr/include/c++/8/bits/stl_construct.h:108
#5 0x0000555555556a98 in std::_Destroy<std::filesystem::__cxx11::path::_Cmpt*> (__first=0x3, __last=0x0)
    at /usr/include/c++/8/bits/stl_construct.h:137
#6 0x00005555555567a9 in std::_Destroy<std::filesystem::__cxx11::path::_Cmpt*, std::filesystem::__cxx11::path::_Cmpt> (__first=0x3, __last=0x0) at /usr/include/c++/8/bits/stl_construct.h:206
#7 0x00005555555564b1 in std::vector<std::filesystem::__cxx11::path::_Cmpt, std::allocator<std::filesystem::__cxx11::path::_Cmpt> >::~vector (this=0x7fffffffe310, __in_chrg=<optimised out>)
    at /usr/include/c++/8/bits/stl_vector.h:567
#8 0x0000555555556314 in std::filesystem::__cxx11::path::~path (this=0x7fffffffe2f0, __in_chrg=<optimised out>)
    at /usr/include/c++/8/bits/fs_path.h:208
#9 0x0000555555556230 in main () at testpath.cpp:5
(gdb) quit
A debugging session is active.

        Inferior 1 [process 2414] will be killed.

Quit anyway? (y or n) y

In , Mpreda (mpreda) wrote :

#include <filesystem>

int main() {
  std::filesystem::path p = "foo";
}

g++ -g --std=c++17 path.cpp

./a.out
Segmentation fault (core dumped)

g++ --version
g++ (Ubuntu 8.3.0-6ubuntu1) 8.3.0

uname -a
Linux x2 5.0.6-050006-generic #201904030534 SMP Wed Apr 3 05:36:14 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

Ubuntu 19.04.

Core was generated by `./a.out'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x000055c2ac25149b in std::vector<std::filesystem::__cxx11::path::_Cmpt, std::allocator<std::filesystem::__cxx11::path::_Cmpt> >::~vector (this=0x23, __in_chrg=<optimized out>) at /usr/include/c++/8/bits/stl_vector.h:567
567 std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
(gdb) bt
#0 0x000055c2ac25149b in std::vector<std::filesystem::__cxx11::path::_Cmpt, std::allocator<std::filesystem::__cxx11::path::_Cmpt> >::~vector (this=0x23, __in_chrg=<optimized out>) at /usr/include/c++/8/bits/stl_vector.h:567
#1 0x000055c2ac251314 in std::filesystem::__cxx11::path::~path (this=0x3, __in_chrg=<optimized out>) at /usr/include/c++/8/bits/fs_path.h:208
#2 0x000055c2ac251f5c in std::filesystem::__cxx11::path::_Cmpt::~_Cmpt (this=0x3, __in_chrg=<optimized out>) at /usr/include/c++/8/bits/fs_path.h:643
#3 0x000055c2ac251f77 in std::_Destroy<std::filesystem::__cxx11::path::_Cmpt> (__pointer=0x3) at /usr/include/c++/8/bits/stl_construct.h:98
#4 0x000055c2ac251e27 in std::_Destroy_aux<false>::__destroy<std::filesystem::__cxx11::path::_Cmpt*> (__first=0x3, __last=0x0) at /usr/include/c++/8/bits/stl_construct.h:108
#5 0x000055c2ac251a98 in std::_Destroy<std::filesystem::__cxx11::path::_Cmpt*> (__first=0x3, __last=0x0) at /usr/include/c++/8/bits/stl_construct.h:137
#6 0x000055c2ac2517a9 in std::_Destroy<std::filesystem::__cxx11::path::_Cmpt*, std::filesystem::__cxx11::path::_Cmpt> (__first=0x3, __last=0x0) at /usr/include/c++/8/bits/stl_construct.h:206
#7 0x000055c2ac2514b1 in std::vector<std::filesystem::__cxx11::path::_Cmpt, std::allocator<std::filesystem::__cxx11::path::_Cmpt> >::~vector (this=0x7ffe3ad201d0, __in_chrg=<optimized out>)
    at /usr/include/c++/8/bits/stl_vector.h:567
#8 0x000055c2ac251314 in std::filesystem::__cxx11::path::~path (this=0x7ffe3ad201b0, __in_chrg=<optimized out>) at /usr/include/c++/8/bits/fs_path.h:208
#9 0x000055c2ac251230 in main () at path.cpp:4

In , Mpreda (mpreda) wrote :

I would hope somebody would take a look and reject this issues as invalid for some reason, because otherwise it's rather severe.

In , Mpreda (mpreda) wrote :

Adding -lstdc++fs fixes the problem with g++ 8.3

g++-9 does not segfault even without -lstdc++fs

g++-9 --version
g++-9 (Ubuntu 9-20190402-1ubuntu1) 9.0.1 20190402 (experimental) [trunk revision 270074]

I just tried with g++ (GCC) 8.3.1 20190223 (Red Hat 8.3.1-2) on Fedora and it works well. But to be able to link, I had to add -lstdc++fs.

Roger Leigh (rleigh) on 2019-04-14
affects: gcc-7 (Ubuntu) → gcc-8 (Ubuntu)
Roger Leigh (rleigh) wrote :

Note that the strategy for GCC packaging in Ubuntu (maybe also in Debian) is the exact opposite of how RedHat handle GCC packaging for RHEL with the Devtoolset stuff.

Ubuntu is always providing the latest version of libstdc++6 from the newest GCC. This is problematic when the older headers are subtly (or not-so-subtly) incompatible with the shared library.

RedHat always uses the copy of libstdc++ provided by the default compiler for the base system. Newer GCC versions link against this library, with newer functionality provided by static linking of the newer libstdc++ for that GCC version.

Both strategies make compromises. But right now, the default GCC version in Ubuntu is actually broken as a result of the former strategy. Perhaps the default libstdc++6 should be provided by the default GCC version, with later versions adding supplementary functionality via a static library?

Matthias Klose (doko) wrote :

No, I think you are bitten by linking with --as-needed as the default., and having the source/object files on the command line before the libraries fixes the issue.

Changed in gcc-8 (Ubuntu):
status: New → Incomplete
Matthias Klose (doko) wrote :

Maybe shipping the default libstdc++ with the default compiler is another option, but then you should make -static-libstdc++ the default. Plus how would you provide dynamic linking with the non-default GCC?

Roger Leigh (rleigh) wrote :

The link order does seem to be significant as you suggested. However, both the linker and run-time linker succeed without error. The failure is inside the path dtor. While --as-needed may well be at fault, it looks like there may be problems with either not reporting errors, or doing the wrong thing, when the link order isn't right.

In , Redi (redi) wrote :

The -lstdc++fs requirement for std::filesystem in GCC 8 is documented in several places:

https://gcc.gnu.org/onlinedocs/gcc-8.3.0/libstdc++/manual/manual/using.html#manual.intro.using.flags
https://gcc.gnu.org/onlinedocs/gcc-8.3.0/libstdc++/manual/manual/status.html#status.iso.2017
https://gcc.gnu.org/onlinedocs/gcc-8.3.0/libstdc++/manual/manual/using_dynamic_or_shared.html#manual.intro.using.linkage.experimental

I don't know why it crashes with Ubuntu, it should be a linker error. I suspect Ubuntu is doing something silly like providing libstdc++.so from GCC 9, which defines std::filesystem::path differently, and so is not compatible with C++17 code compiled using GCC 8.

In , Redi (redi) wrote :

Although if you link with -lstdc++fs then it should work OK, because the incompatible std::filesystem symbols in libstdc++.so.6.0.26 won't be used.

Matthias Klose (doko) wrote :

there is a link error with:

$ g++-8 -static-libstdc++ -std=c++17 -lstdc++fs -g3 -o testpath testpath.cpp
/usr/bin/ld: /tmp/ccWrH4Ho.o: in function `std::filesystem::__cxx11::path::path<char [5], std::filesystem::__cxx11::path>(char const (&) [5], std::filesystem::__cxx11::path::format)':
/usr/include/c++/8/bits/fs_path.h:184: undefined reference to `std::filesystem::__cxx11::path::_M_split_cmpts()'
collect2: error: ld returned 1 exit status

you won't see it with dynamic linking because in 9, the code from libstdc++fs is now integrated in the libstdc++ library.

Jonathan Wakely (jwakely) wrote :

The GCC 8 std::filesystem (and std::experimental::filesystem) symbols are in libstdc++fs.a which is only provided as a static library, so link order does matter. If you don't tell the linker to use it after the objects that require it, then no symbols from libstdc++fs.a will be used.

In GCC 9 the std::experimental::filesystem symbols are still in libstdc++fs.a but the std::filesystem symbols are in libstdc++.so.6.0.26 now, but they're incompatible with the GCC 8 definitions. In your problematic link no symbols were used from libstdc++fs.a, so the linker finds the GCC 9 ones in libstdc++.so.6.0.25 and uses them, but that leads to crashes.

It would have been possible to make the GCC 8 and 9 std::filesystem symbols mangle differently, and maybe I should do that for GCC 8.4, but for now the short answer is "C++17 support in GCC 8 is experimental, the onus is on you to link correctly".

Since this problem is specific to Ubuntu, due to mixing gcc-8 and libstdc++.so.6.0.26, another possibility would be for Ubuntu's gcc-8 to reorder the linker arguments. If -lstdc++fs is given it could be moved to after the object files (but before the implicit -lstdc++ option that g++ adds).

Another option would be to make g++ simply link to -lstdc++fs implicitly, as it does for -lstdc++. Unless the user adds -Wl,--whole-archive (and doesn't follow it with -Wl,--no-whole-archive) that should be harmless because the symbols in libstdc++fs.a will only be used if actually needed.

Jonathan Wakely (jwakely) wrote :

Gah, typo:

> so the linker finds the GCC 9 ones in libstdc++.so.6.0.25 and uses them

That should have said libstdc++.so.6.0.26 - sorry for any confusion.

In , Mpreda (mpreda) wrote :

OK, thanks.

So if on Ubuntu 19.04, the default compiler produces without errors/warnings, from valid source code, an executable that crashes, that's programmer error?!

I understand the explanation, but there is a problem. Maybe the bug is not with gcc but with Ubuntu, but a bug there is.

In , Redi (redi) wrote :

See https://bugs.launchpad.net/ubuntu/+source/gcc-8/+bug/1824721 where I said:

"for now the short answer is "C++17 support in GCC 8 is experimental, the onus is on you to link correctly"

Changed in gcc:
importance: Unknown → Medium
status: Unknown → Invalid
Matthias Klose (doko) on 2019-04-18
Changed in gcc-8 (Ubuntu):
status: Incomplete → Triaged

that's now mitigated by a local patch, always linking with -lstdc++fs.

https://salsa.debian.org/toolchain-team/gcc/blob/gcc-8-debian/debian/patches/pr90050.diff

Launchpad Janitor (janitor) wrote :

This bug was fixed in the package gcc-8 - 8.3.0-7ubuntu1

---------------
gcc-8 (8.3.0-7ubuntu1) eoan; urgency=medium

  * Merge with Debian; remaining changes:
    - Build from upstream sources.
    - Don't built common libraries now build from GCC 9.

gcc-8 (8.3.0-7) unstable; urgency=medium

  * Update to SVN 20190428 (r270630) from the gcc-8-branch.
    - Fix PR target/89877 (ARC), PR target/84369 (PPC),
      PR tree-optimization/85762, PR tree-optimization/87008,
      PR tree-optimization/85459, PR target/87532 (PPC),
      PR target/87532 (PPC), PR ipa/89693, PR middle-end/88587,
      PR tree-optimization/90018, PR target/90024 (ARM),
      PR target/89945 (ARM), PR fortran/87352, PR fortran/89981,
      PR fortran/89904, PR libgfortran/79540, PR fortran/87127,
      PR rtl-optimization/87979, PR rtl-optimization/84032.
  * Fix PR c++/90050, always link with libstdc++fs.a. LP: #1824721.
  * Fix PR bootstrap/87338 on ia64 (James Clarke). Closes: #927976.

 -- Matthias Klose <email address hidden> Sun, 28 Apr 2019 09:51:11 +0200

Changed in gcc-8 (Ubuntu):
status: Triaged → Fix Released
To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.