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 | 
      |            ^

Reply via email to