https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98465
--- Comment #14 from Martin Sebor <msebor at gcc dot gnu.org> ---
Smallish test case independent of libstdc++ that reproduces both the false
positive (due to the missing aliasing constraint) and its absence (due to a
bug/limitation in tree_inlined_location). With -Wsystem-headers GCC issues two
instances of the false positive, one for f() and the other for g():
$ cat pr98465.C && gcc -O2 -S -Wall -Wextra pr98465.C
# 1 "pr98465.h" 1 3
typedef __SIZE_TYPE__ size_type;
typedef __UINTPTR_TYPE__ uintptr_t;
struct S {
char *dta;
size_type cap, siz;
bool _M_disjunct (const char *s) const {
return ((uintptr_t)s < (uintptr_t)dta
|| (uintptr_t)dta + siz < (uintptr_t)s);
}
void assign (const char *s, size_type n) {
assign2 (s, n);
}
void assign2 (const char *s, size_type n) {
_M_replace (0, siz, s, n);
}
void _M_replace (size_type pos, size_type len1, const char* s,
const size_type len2) {
const size_type old_size = siz;
const size_type new_size = old_size + len2 - len1;
if (new_size <= cap)
{
char *p = dta + pos;
const size_type how_much = old_size - pos - len1;
if (_M_disjunct (s))
{
if (how_much && len1 != len2)
__builtin_memmove (p + len2, p + len1, how_much);
if (len2)
__builtin_memcpy (p, s, len2);
}
else
{
if (len2 && len2 <= len1)
__builtin_memmove (p, s, len2);
if (how_much && len1 != len2)
__builtin_memmove (p + len2, p + len1, how_much);
if (len2 > len1)
{
if (s + len2 <= p + len1)
__builtin_memmove (p, s, len2);
else if (s >= p + len1)
__builtin_memcpy (p, s + len2 - len1, len2);
else
{
const size_type nleft = (p + len1) - s;
__builtin_memmove (p, s, nleft);
__builtin_memcpy (p + nleft, p + len2,
len2 - nleft);
}
}
}
}
}
};
# 1 "pr98465.C"
const char a[] = { 1, 2 };
void f (S &s)
{
s.assign (a, 2); // no warning
}
const char b[] = { 2, 3 };
void g (S &s)
{
s.assign2 (b, 2); // bogus -Wstringop-overread
}
In file included from pr98465.C:1:
In member function ‘void S::_M_replace(size_type, size_type, const char*,
size_type)’,
inlined from ‘void S::assign2(const char*, size_type)’ at pr98465.h:19:16,
inlined from ‘void g(S&)’ at pr98465.C:13:13:
pr98465.h:50:24: warning: ‘void* __builtin_memcpy(void*, const void*, long
unsigned int)’ reading 2 bytes from a region of size 1 [-Wstringop-overread]
In file included from pr98465.C:1:
pr98465.C: In function ‘void g(S&)’:
pr98465.C:9:12: note: at offset [1, 2] into source object ‘b’ of size 2
9 |
| ^