https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90132

Martin Sebor <msebor at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |diagnostic
             Status|UNCONFIRMED                 |NEW
   Last reconfirmed|                            |2019-04-17
                 CC|                            |msebor at gcc dot gnu.org
             Blocks|                            |88443
     Ever confirmed|0                           |1

--- Comment #1 from Martin Sebor <msebor at gcc dot gnu.org> ---
I can reproduce the warning without -fPIC:

$ (cd /build/gcc-svn-self/libdecnumber  && /build/gcc-svn/gcc/xgcc -B
/build/gcc-svn/gcc  -I/src/gcc/svn/libdecnumber -I.  -O3 -g3 -W -Wall
-Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition
-Wmissing-format-attribute -Wcast-qual -pedantic -Wno-long-long  -fno-lto
-I/src/gcc/svn/libdecnumber -I. -S /src/gcc/svn/libdecnumber/decNumber.c)
/src/gcc/svn/libdecnumber/decNumber.c: In function ‘decNumberPower’:
cc1: warning: ‘__builtin_memcpy’ reading 2 or more bytes from a region of size
0 [-Wstringop-overflow=]
$ 

The variable being read is dnOne:

  <bb 94> [local count: 3614127]:
  # iftmp.231_443 = PHI <iftmp.231_438(92), iftmp.231_442(93)>
  smsup_444 = &dnOne.lsu + iftmp.231_443;
  if (&MEM[(void *)&dnOne + 12B] < smsup_444)
    goto <bb 95>; [89.00%]
  else
    goto <bb 97>; [11.00%]

  <bb 95> [local count: 3216573]:
  _110 = (unsigned long) smsup_444;
  _550 = (unsigned long) &MEM[(void *)&dnOne + 12B];
  _568 = ~_550;
  _525 = _110 + _568;
  _524 = _525 >> 1;
  _520 = _524 + 1;
  _518 = _520 * 2;
  __builtin_memcpy (d_434, &MEM[(void *)&dnOne + 12B], _518);

The offset 12 in the MEM_REF corresponds to sizeof (decnumber). 
compute_builtin_object_size() returns zero for &MEM[(void *)&dnOne + 12B] and
_518's range is ~[1, 1], so either zero or 2 or more.  The warning doesn't
consider the unlikely case of zero and treats the anti-range as [2, SIZE_MAX].

The missing location information suggests the memcpy call is the result of some
transformation.  The reference to smsup implies it comes from this loop in
decNumberCopy() (the only function in the translation unit that defines the
smsup variable):

  if (src->digits>3) {
    const uint16_t *smsup, *s;
    uint16_t *d;


    d=dest->lsu+1;
    smsup=src->lsu+((src->digits)<=49?d2utable[src->digits]:((src->digits)+3
-1)/3);
    for (s=src->lsu+1; s<smsup; s++, d++) *d=*s;
    }
  return dest;
  }

The trailing one-element decnumber::lsu array is being used as a flexible-array
member with decnumber::digits corresponding to the number of elements.  The
value src->lsu+1 is past the end of the dnOne object but smsup has one of two
values: src->lsu + d2utable[src->digits] or src->lsu + 1, and the first one
doesn't look determinate because dnOne is also used as some sort of a temporary
by decNumberPower and its digits member (initially set to 1) is overwritten. 
So the loop gets transformed into memcpy that reads some number other than 1
from an object of size zero.

Adding an assertion like in the otherwise untested patch below should let GCC
see that dnOne.digits is unchanged.  I don't know enough about the library to
tell if that's actually correct or what the correct macro or value to use here
might be.

===================================================================
--- libdecnumber/decNumber.c    (revision 270418)
+++ libdecnumber/decNumber.c    (working copy)
@@ -2188,6 +2188,8 @@ decNumber * decNumberPower(decNumber *res, const d
            }
          /* [inv now points to big-enough buffer or allocated storage] */
          decNumberCopy(inv, dac);      /* copy the 1/lhs */
+         if (dnOne.digits > 1)
+           __builtin_unreachable ();
          decNumberCopy(dac, &dnOne);   /* restore acc=1 */
          lhs=inv;                      /* .. and go forward with new lhs */
        #if DECSUBSET


Referenced Bugs:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88443
[Bug 88443] [meta-bug] bogus/missing -Wstringop-overflow warnings

Reply via email to