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

Reply via email to