Bug 103332

Summary: [12 Regression] Spurious -Wstringop-overflow on string concatenation in libstdc++ tests
Product: gcc Reporter: Jonathan Wakely <redi>
Component: tree-optimizationAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED DUPLICATE    
Severity: normal CC: jason, msebor
Priority: P3 Keywords: diagnostic
Version: 12.0   
Target Milestone: ---   
See Also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102958
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103483
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103534
Host: Target:
Build: Known to work:
Known to fail: 12.0 Last reconfirmed: 2021-11-25 00:00:00
Bug Depends on:    
Bug Blocks: 88443    

Description Jonathan Wakely 2021-11-19 15:52:46 UTC
In the $objdir/$target/libstdc++-v3/testsuite dir, running:

make check RUNTESTFLAGS="conformance.exp=21_strings/basic_string/operators/char/1.cc --target_board=unix/-D_GLIBCXX_DEBUG"

Results in:

In file included from /home/jwakely/build/powerpc64le-unknown-linux-gnu/libstdc++-v3/include/string:40,^M
                 from /home/jwakely/src/gcc/libstdc++-v3/testsuite/21_strings/basic_string/operators/char/1.cc:22:^M
In static member function 'static std::char_traits<char>::char_type* std::char_traits<char>::copy(std::char_traits<char>::char_type*, const std::char_traits<char>::char_type*, std::size_t)',^M
    inlined from 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' at /home/jwakely/build/powerpc64le-unknown-linux-gnu/libstdc++-v3/include/bits/basic_string.h:675,^M
    inlined from 'std::__cxx11::basic_string<_CharT, _Traits, _Allocator> std::operator+(std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&&, const _CharT*) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' at /home/jwakely/build/powerpc64le-unknown-linux-gnu/libstdc++-v3/include/bits/basic_string.h:3552,^M
    inlined from 'int test01()' at /home/jwakely/src/gcc/libstdc++-v3/testsuite/21_strings/basic_string/operators/char/1.cc:34:^M
/home/jwakely/build/powerpc64le-unknown-linux-gnu/libstdc++-v3/include/bits/char_traits.h:423: warning: 'void* __builtin_memcpy(void*, const void*, long unsigned int)' writing 17 bytes into a region of size 16 overflows the destination [-Wstringop-overflow=]^M
/home/jwakely/src/gcc/libstdc++-v3/testsuite/21_strings/basic_string/operators/char/1.cc: In function 'int test01()':^M
/home/jwakely/src/gcc/libstdc++-v3/testsuite/21_strings/basic_string/operators/char/1.cc:34: note: at offset 16 into destination object '<anonymous>' of size 32^M
FAIL: 21_strings/basic_string/operators/char/1.cc (test for excess errors)
Excess errors:
/home/jwakely/build/powerpc64le-unknown-linux-gnu/libstdc++-v3/include/bits/char_traits.h:423: warning: 'void* __builtin_memcpy(void*, const void*, long unsigned int)' writing 17 bytes into a region of size 16 overflows the destination [-Wstringop-overflow=]


And:

make check RUNTESTFLAGS="conformance.exp=21_strings/basic_string/capacity/char/1.cc --target_board=unix/-std=gnu++20"

results in:

In file included from /home/jwakely/build/powerpc64le-unknown-linux-gnu/libstdc++-v3/include/string:40,^M
                 from /home/jwakely/src/gcc/libstdc++-v3/testsuite/21_strings/basic_string/capacity/char/1.cc:22:^M
In static member function 'static constexpr std::char_traits<char>::char_type* std::char_traits<char>::copy(std::char_traits<char>::char_type*, const std::char_traits<char>::char_type*, std::size_t)',^M
    inlined from 'static constexpr void std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::_S_copy(_CharT*, const _CharT*, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' at /home/jwakely/build/powerpc64le-unknown-linux-gnu/libstdc++-v3/include/bits/basic_string.h:423,^M
    inlined from 'static constexpr void std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::_S_copy(_CharT*, const _CharT*, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' at /home/jwakely/build/powerpc64le-unknown-linux-gnu/libstdc++-v3/include/bits/basic_string.h:418,^M
    inlined from 'constexpr std::__cxx11::basic_string<_CharT, _Traits, _Allocator>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::_M_append(const _CharT*, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' at /home/jwakely/build/powerpc64le-unknown-linux-gnu/libstdc++-v3/include/bits/basic_string.tcc:417,^M
    inlined from 'constexpr std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::append(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' at /home/jwakely/build/powerpc64le-unknown-linux-gnu/libstdc++-v3/include/bits/basic_string.h:1385,^M
    inlined from 'constexpr std::__cxx11::basic_string<_CharT, _Traits, _Allocator> std::operator+(const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&, const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' at /home/jwakely/build/powerpc64le-unknown-linux-gnu/libstdc++-v3/include/bits/basic_string.h:3433,^M
    inlined from 'void test01()' at /home/jwakely/src/gcc/libstdc++-v3/testsuite/21_strings/basic_string/capacity/char/1.cc:102:^M
/home/jwakely/build/powerpc64le-unknown-linux-gnu/libstdc++-v3/include/bits/char_traits.h:423: warning: 'void* __builtin_memcpy(void*, const void*, long unsigned int)' specified bound between 18446744073709551586 and 18446744073709551615 exceeds maximum object size 9223372036854775807 [-Wstringop-overflow=]^M
FAIL: 21_strings/basic_string/capacity/char/1.cc (test for excess errors)
Excess errors:
/home/jwakely/build/powerpc64le-unknown-linux-gnu/libstdc++-v3/include/bits/char_traits.h:423: warning: 'void* __builtin_memcpy(void*, const void*, long unsigned int)' specified bound between 18446744073709551586 and 18446744073709551615 exceeds maximum object size 9223372036854775807 [-Wstringop-overflow=]



And:

make check  RUNTESTFLAGS"=conformance.exp=experimental/filesystem/path/factory/u8path-char8_t.cc --target_board=unix/-std=gnu++20"


results in:

[...]
FAIL: experimental/filesystem/path/factory/u8path-char8_t.cc (test for excess errors)
Excess errors:
/home/jwakely/build/powerpc64le-unknown-linux-gnu/libstdc++-v3/include/bits/char_traits.h:423: warning: 'void* __builtin_memcpy(void*, const void*, long unsigned int)' reading between 16 and 9223372036854775806 bytes from a region of size 10 [-Wstringop-overread]
/home/jwakely/build/powerpc64le-unknown-linux-gnu/libstdc++-v3/include/bits/char_traits.h:423: warning: 'void* __builtin_memcpy(void*, const void*, long unsigned int)' reading between 16 and 9223372036854775806 bytes from a region of size 10 [-Wstringop-overread]



These are all bogus, as far as I can tell. e.g. for the last one, we read 9 bytes from a string literal that is 10 bytes long (including the null) and memcpy it into a buffer that is 16 bytes in size. That doesn't overflow.
Comment 1 Martin Sebor 2021-11-19 16:03:52 UTC
Suspect at least some of these might be due to the same underlying problem as pr102958.  I suppressed a subset of these warnings in g:sy9a27acc30a34b7854db32eac562306cebac6fa1e.
Comment 2 Jonathan Wakely 2021-11-19 17:59:21 UTC
(In reply to Martin Sebor from comment #1)
> I suppressed a subset of these warnings in
> g:9a27acc30a34b7854db32eac562306cebac6fa1e.

Ah yes, I'll add the same again then, thanks.
Comment 3 GCC Commits 2021-11-19 18:16:35 UTC
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>:

https://gcc.gnu.org/g:b8f2efaed02e8b03d215d74e42d3707761772f64

commit r12-5414-gb8f2efaed02e8b03d215d74e42d3707761772f64
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Nov 19 18:13:10 2021 +0000

    libstdc++: Suppress -Wstringop warnings [PR103332]
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/103332
            PR libstdc++/102958
            * testsuite/21_strings/basic_string/capacity/char/1.cc: Add
            -Wno-stringop-overflow.
            * testsuite/21_strings/basic_string/operators/char/1.cc:
            Likewise.
            * testsuite/experimental/filesystem/path/factory/u8path-char8_t.cc:
            Add -Wno-stringop-overread.
Comment 4 Andrew Pinski 2021-11-25 19:22:09 UTC
.
Comment 5 Martin Sebor 2021-12-08 23:30:42 UTC
The first warning is for the invalid memcpy() call below:

  struct string D.35215;
  ...
  <bb 3> [local count: 1073312331]:
  D.35215._M_string_length = 16;
  _62 = D.35215._M_dataplus._M_p;
  MEM[(char_type &)_62 + 16] = 0;
  D.35222 ={v} {CLOBBER};
  MEM[(struct _Alloc_hider *)&D.35222] ={v} {CLOBBER};
  MEM[(struct _Alloc_hider *)&D.35222]._M_p = &D.35222.D.28102._M_local_buf;
  if (&MEM <const char[16]> [(void *)&D.35215 + 16B] == _62)
    goto <bb 4>; [30.00%]
  else
    goto <bb 5>; [70.00%]

  <bb 4> [local count: 157390518]:
  __builtin_memcpy (&D.35222.D.28102._M_local_buf, &MEM <const char[16]> [(void *)&D.35215 + 16B], 17);
  goto <bb 6>; [100.00%]

sizeof std::string::_M_local_buf is 16 but the call writes 17 bytes into it, so the call is invalid.

I only see the warning at -O1 (and with -D_GLIBCXX_DEBUG).  It also goes away if I force std::string::_M_mutate to be inlined.  _M_mutate allocates the dynamic string so with it inlined GCC can determine that the local buffer is no longer used and eliminate the invalid call.  So as in the other cases we have seen recently, this false positive is due to some optimizer limitations caused by the combination of -O1 and a decision to throttle inlining.  The second warning is due to the same issue.  It too goes away with more aggressive inlining (on x86_64 setting -finline-limit=200 avoids it).
Comment 6 GCC Commits 2021-12-09 23:24:37 UTC
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>:

https://gcc.gnu.org/g:f8463b0e3ec2438b4cfb8c9a468d59761db2c8a0

commit r12-5874-gf8463b0e3ec2438b4cfb8c9a468d59761db2c8a0
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Dec 2 13:19:41 2021 +0000

    libstdc++: Disable over-zealous warnings about std::string copies [PR103332]
    
    These warnings are triggered by perfectly valid code using std::string.
    They're particularly bad when --enable-fully-dynamic-string is used,
    because even std::string().begin() will give a warning.
    
    Use pragmas to stop the troublesome warnings for copies done by
    std::char_traits.
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/103332
            PR libstdc++/102958
            PR libstdc++/103483
            * include/bits/char_traits.h: Suppress stringop and array-bounds
            warnings.
Comment 7 Jason Merrill 2021-12-13 16:11:52 UTC
Same append issue.

*** This bug has been marked as a duplicate of bug 103534 ***