问题
Consider the following program:
#include <iostream>
#include <string>
int main()
{
std::string s;
std::getline(std::cin, s);
return 0;
}
I try to build it with various flags and run as echo foo | ./prog
.
If I build it with clang 5.0 or gcc 7.1 (or 7.2) with optimization from -O0
to -O3
, it works as expected. But if I add -flto
to any of these configurations, it crashes immediately with the following backtrace:
/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 reports the same in a slightly more readable way:
==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"
Also it works OK with --std=c++14
and below even with LTO enabled.
So what is the problem? Is it a bug in LTO implementation for C++17 in both compilers? Or just the libstdc++
is compiled with wrong flags? I use opensuse 42.3 and the standard library is installed from repositories.
Can it be worked around somehow?
回答1:
For gcc this looks like this bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82172.
There are a number of workarounds, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82172#c3. One of them is to use -D_GLIBCXX_USE_CXX11_ABI=1
:
g++ -D_GLIBCXX_USE_CXX11_ABI=1 --std=c++17 -flto prog.cpp
See also the same problem here flto crash with gcc7.2.
回答2:
Following ks1322's links, I finally landed to binutils bug page, which describes the root of the problem.
The bug was finally fixed in binutils 2.30 and backported to binutils 2.29 and 2.28. Updating to binutils 2.29 fixed the test example, but my actual build was still affected.
I figured out that one of my project's dependencies (I use CMake and external project module) was build without LTO. Adding -flto
to all dependencies and using appropriate archiver (i.e. gcc-ar
instead of ar
) solved the problem completely.
来源:https://stackoverflow.com/questions/47456530/lto-causes-crash-in-standard-library