https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116494
Bug ID: 116494 Summary: std::string::replace uses memcpy incorrectly and warns about it Product: gcc Version: 13.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: grisumbras at yandex dot ru Target Milestone: --- When compiled with -std=c++20 -O3 -Wall -Werror this code: #include <string> bool foo(std::string s1) { s1.replace(1, 1, s1.data(), s1.size()); return s1.size(); } fails with a warning about incorrect use of __builtin_memcpy. As far as I can see, inside _M_replace the call to _M_disjunct paradoxically determines that s1.data() is not contained in s1's buffer. Because of that _M_replace then uses the wrong branch and uses memcpy, when it shouldn't have. This only happens with -O3 and with -std=c++20 (or later). I originally discovered this behaviour on GCC 13, but then found out that it is also reproducible on every version of GCC since 12. Locally tested on stock GCC 13 on Ubuntu 24.04. Output of g++ -v -save-temps -std=c++20 -O3 -Wall -Werror -c 2.cpp Using built-in specs. COLLECT_GCC=g++ OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa OFFLOAD_TARGET_DEFAULT=1 Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 13.2.0-23ubuntu4' --with-bugurl=file:///usr/share/doc/gcc-13/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-13 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-libstdcxx-backtrace --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-13-uJ7kn6/gcc-13-13.2.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-13-uJ7kn6/gcc-13-13.2.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 13.2.0 (Ubuntu 13.2.0-23ubuntu4) COLLECT_GCC_OPTIONS='-v' '-save-temps' '-std=c++20' '-O3' '-Wall' '-Werror' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' /usr/libexec/gcc/x86_64-linux-gnu/13/cc1plus -E -quiet -v -imultiarch x86_64-linux-gnu -D_GNU_SOURCE 2.cpp -mtune=generic -march=x86-64 -std=c++20 -Wall -Werror -O3 -fpch-preprocess -D_FORTIFY_SOURCE=3 -fasynchronous-unwind-tables -fstack-protector-strong -Wformat-security -fstack-clash-protection -fcf-protection -o 2.ii ignoring duplicate directory "/usr/include/x86_64-linux-gnu/c++/13" ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu" ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/include-fixed/x86_64-linux-gnu" ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/include-fixed" ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include" #include "..." search starts here: #include <...> search starts here: /usr/include/c++/13 /usr/include/x86_64-linux-gnu/c++/13 /usr/include/c++/13/backward /usr/lib/gcc/x86_64-linux-gnu/13/include /usr/local/include /usr/include/x86_64-linux-gnu /usr/include End of search list. COLLECT_GCC_OPTIONS='-v' '-save-temps' '-std=c++20' '-O3' '-Wall' '-Werror' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' /usr/libexec/gcc/x86_64-linux-gnu/13/cc1plus -fpreprocessed 2.ii -D_FORTIFY_SOURCE=3 -quiet -dumpbase 2.cpp -dumpbase-ext .cpp -mtune=generic -march=x86-64 -O3 -Wall -Werror -std=c++20 -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat-security -fstack-clash-protection -fcf-protection -o 2.s GNU C++20 (Ubuntu 13.2.0-23ubuntu4) version 13.2.0 (x86_64-linux-gnu) compiled by GNU C version 13.2.0, GMP version 6.3.0, MPFR version 4.2.1, MPC version 1.3.1, isl version isl-0.26-GMP GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 Compiler executable checksum: 4e0f319cd9945d8f5a9eeeeec1481ba5 In file included from /usr/include/c++/13/string:42, from 2.cpp:1: In static member function ‘static constexpr std::char_traits<char>::char_type* std::char_traits<char>::copy(char_type*, const char_type*, std::size_t)’, inlined from ‘static constexpr void std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::_S_copy(_CharT*, const _CharT*, size_type) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’ at /usr/include/c++/13/bits/basic_string.h:430:21, inlined from ‘constexpr std::__cxx11::basic_string<_CharT, _Traits, _Allocator>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::_M_replace(size_type, size_type, const _CharT*, size_type) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’ at /usr/include/c++/13/bits/basic_string.tcc:542:16, inlined from ‘constexpr std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::replace(size_type, size_type, const _CharT*, size_type) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’ at /usr/include/c++/13/bits/basic_string.h:2208:19, inlined from ‘bool foo(std::string)’ at 2.cpp:5:13: /usr/include/c++/13/bits/char_traits.h:435:56: error: ‘void* __builtin_memcpy(void*, const void*, long unsigned int)’ accessing 2 or more bytes at offsets 1 and 0 overlaps 1 or more bytes at offset 1 [-Werror=restrict] 435 | return static_cast<char_type*>(__builtin_memcpy(__s1, __s2, __n)); | ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~ cc1plus: all warnings being treated as errors