web-dev-qa-db-ja.com

std :: filesystem :: pathを関数segfaultsに渡す

関数の引数としてstd::filesystem::pathを使用しようとすると、マシンでsegfaultが発生します。これは最小限の例です:

#include <filesystem>

void thing(const std::filesystem::path& p) {
    return;
}

int main() {
    thing("test");
    return 0;
}

このスニペットにより、gdbから次のバックトレースが得られます。

#0  0x0000563a5a3814b3 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  0x0000563a5a38132c in std::filesystem::__cxx11::path::~path (this=0x3, __in_chrg=<optimized out>) at /usr/include/c++/8/bits/fs_path.h:208
#2  0x0000563a5a381f74 in std::filesystem::__cxx11::path::_Cmpt::~_Cmpt (this=0x3, __in_chrg=<optimized out>) at /usr/include/c++/8/bits/fs_path.h:643
#3  0x0000563a5a381f8f in std::_Destroy<std::filesystem::__cxx11::path::_Cmpt> (__pointer=0x3) at /usr/include/c++/8/bits/stl_construct.h:98
#4  0x0000563a5a381e3f 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  0x0000563a5a381ab0 in std::_Destroy<std::filesystem::__cxx11::path::_Cmpt*> (__first=0x3, __last=0x0) at /usr/include/c++/8/bits/stl_construct.h:137
#6  0x0000563a5a3817c1 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  0x0000563a5a3814c9 in std::vector<std::filesystem::__cxx11::path::_Cmpt, std::allocator<std::filesystem::__cxx11::path::_Cmpt> >::~vector (this=0x7ffd198df8a0 = {...}, __in_chrg=<optimized out>) at /usr/include/c++/8/bits/stl_vector.h:567
#8  0x0000563a5a38132c in std::filesystem::__cxx11::path::~path (this=0x7ffd198df880<error reading variable: Cannot access memory at address 0x2b>, __in_chrg=<optimized out>) at /usr/include/c++/8/bits/fs_path.h:208
#9  0x0000563a5a381247 in main () at /home/user/CLionProjects/test/main.cpp:8
#10 0x00007fd6bb96ab6b in __libc_start_main (main=0x563a5a381200 <main()>, argc=1, argv=0x7ffd198df9b8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7ffd198df9a8) at ../csu/libc-start.c:308
#11 0x0000563a5a38113a in _start ()

私はUbuntu 19.10でGCC 8.3を使用しています。Windowsで問題なくこのコードをコンパイルして実行したため、libstdc++のバグである可能性があります

8
Astrognome

問題は、Ubuntuが単一のインストールでGCCバージョンを混在させることだと思います。 Ubuntuでは、デフォルトのGCCはバージョン8ですが、libstdc++.so.6ライブラリはGCC 9から提供されます。GCC8では、std::filesystem定義は別のライブラリlibstdc++fs.aにあり、明示的にリンクする必要があります。 GCC 9では、std::filesystemシンボルはメインのlibstdc++.soライブラリにあります。 Ubuntuのインストールが混同されているため、libstdc++.soのGCC 9シンボルが、GCC 8でコンパイルされたコードの未定義の参照を満たすことができますはずですlibstdc++fs.aが満足する。 GCC 9のstd::filesystemシンボルは、GCC 8のこれらのシンボルの試験的なバージョンと互換性がないため、リンクは問題ないように見えますが、実行時にクラッシュします。

-lstdc++fsとリンクし、オプションがすべてのオブジェクトファイルの後にあることを確認すると、正しく機能するはずです。これはうまくいくはずです:

g++ foo.o bar.o -lstdc++fs

しかし、これは動作しません

g++ -lstdc++fs foo.o bar.o

gcc-8オプションが他のすべての入力ファイルの後に来るようにすることで、これを修正するためにUbuntu -lstdc++fsパッケージのアップデートがあるはずです。詳細については https://bugs.launchpad.net/ubuntu/+source/gcc-8/+bug/1824721 を参照してください

gcc-9を使用したコンパイルも機能します。GCC9を使用してコンパイルする場合、-lstdc++fsstd::filesystemにリンクする必要がないためです(GCC 9ではstd::experimental::filesystemシンボルにのみ必要です)。 。

11
Jonathan Wakely

このPPAからGCCとG ++ 9をインストールすることで、この問題を修正できました: https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test

1
Astrognome

リンクしてください-lstdc++fsライブラリ、ソースファイルがfileSys.cppであると見なして、次のようにコンパイルします。
g++ -std=c++17 fileSys.cpp -lstdc++fs -o fs

使ってます GCC 8.1.0およびUbuntu 16.04.1 LTS
このトピックに関してすでに同様の質問があり、それを ファイルシステムリンカーエラー で見つけることができます

0
Vikas Awadhiya