LTO导致标准库崩溃

时间:2017-11-23 13:19:01

标签: c++ gcc segmentation-fault clang lto

考虑以下计划:

#include <iostream>
#include <string>

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

我尝试使用各种标志构建它并以echo foo | ./prog运行。

如果我使用clang 5.0或gcc 7.1(或7.2)构建它并进行优化-O0-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"

即使启用了LTO,它也可以在--std=c++14及以下使用。

那么问题是什么?这是两个编译器中C ++ 17的LTO实现中的错误吗?或者只是用错误的标志编译libstdc++?我使用的是opensuse 42.3,标准库是从存储库安装的。

可以以某种方式解决吗?

2 个答案:

答案 0 :(得分:2)

对于gcc,这看起来像这个bug:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82172

有许多解决方法,请参阅https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82172#c3。其中之一是使用:s/\(\S\) \ze)/\1/g

-D_GLIBCXX_USE_CXX11_ABI=1

另请参阅flto crash with gcc7.2中的相同问题。

答案 1 :(得分:1)

在ks1322的链接之后,我终于登陆了binutils bug page, 描述问题的根源。

该错误最终在binutils 2.30中修复,并向后移植到binutils 2.29和2.28。更新到binutils 2.29修复了测试示例,但我的实际构建仍然受到影响。

我发现我的项目依赖项之一(我使用CMake和external project module)是在没有LTO的情况下构建的。将-flto添加到所有依赖项并使用适当的归档程序(即gcc-ar而不是ar)可以完全解决问题。