1

次のプログラムを検討してください。

#include <iostream>
#include <string>

int main()
{
        std::string s;
        std::getline(std::cin, s);
        return 0;
}

さまざまなフラグを付けてビルドし、として実行しようとしましたecho foo | ./prog

-O0から最適化してclang 5.0またはgcc 7.1(または7.2)でビルドすると-O3、期待どおりに動作します。しかし、これらの構成のいずれかに追加-fltoすると、次のバックトレースですぐにクラッシュします。

/lib64/libc.so.6(+0x721af)[0x7f596b08e1af]
/lib64/libc.so.6(+0x77706)[0x7f596b093706]
/lib64/libc.so.6(+0x78453)[0x7f596b094453]
/usr/lib64/libstdc++.so.6(_ZNSs7reserveEm+0x85)[0x7f596b9ac055]
/usr/lib64/libstdc++.so.6(_ZSt7getlineIcSt11char_traitsIcESaIcEERSt13basic_istreamIT_T0_ES7_RSbIS4_S5_T1_ES4_+0x175)[0x7f596b984c05]
./a.out[0x400d7d]
./a.out[0x400c32]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x7f596b03c6e5]
./a.out[0x400ab9]

Valgrind は、もう少し読みやすい方法で同じことを報告します。

==30863== Invalid free() / delete / delete[] / realloc()
==30863==    at 0x4C2A8DC: operator delete(void*) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==30863==    by 0x4F0E054: std::string::reserve(unsigned long) (in /usr/lib64/libstdc++.so.6.0.24)
==30863==    by 0x4EE6C04: std::basic_istream<char, std::char_traits<char> >& std::getline<char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, char) (in /usr/lib64/libstdc++.so.6.0.24)
==30863==    by 0x40091B: main (in /path/to/prog)
==30863==  Address 0x6011c0 is 0 bytes inside data symbol "_ZNSs4_Rep20_S_empty_rep_storageE"

また--std=c++14、LTOを有効にしても、以下で問題なく動作します。

それで、問題は何ですか?両方のコンパイラでの C++17 の LTO 実装のバグですか? それともlibstdc++、間違ったフラグでコンパイルされているだけですか? 私はopensuse 42.3を使用しており、標準ライブラリはリポジトリからインストールされています。

なんとか回避できますか?

4

2 に答える 2