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