LTO causes crash in standard library

北战南征 提交于 2021-01-28 07:54:17

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!