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

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

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |diagnostic
             Status|UNCONFIRMED                 |ASSIGNED
   Last reconfirmed|                            |2017-12-20
           Assignee|unassigned at gcc dot gnu.org      |msebor at gcc dot 
gnu.org
     Ever confirmed|0                           |1

--- Comment #1 from Martin Sebor <msebor at gcc dot gnu.org> ---
Confirmed with an arm-linux-gnueabi cross-compiler and the test case below.

Most (all?) back-ends transform the strcpy call into memcpy first (in the
handle_builtin_strcpy function in tree-ssa-strlen.c), just after warning for
the out-of-bounds offset.  After transforming the call handle_builtin_strcpy
also sets the no-warning bit on the new statement to prevent warning on it
again.

Most back-ends (or at least some, including x86_64) also transform the memcpy
call into MEM_REF.  The arm compiler, however, doesn't and leaves the invalid
memcpy call alone.  The invalid memcpy call is ultimately noticed by the
-Wstringop-overflow checker which hasn't been updated to check the no-warning
bit.  That results in the duplicate warning.

I think this points out not just (minor) issue with the warning but a more
serious weakness in the buffer overflow detection and prevention
(_FORTIFY_SOURCE) which lets this bug slip through.  This is one of the
downsides of allowing even invalid calls to be folded.

$ cat a.c && gcc -O2 -S -Wall -fdump-tree-optimized=/dev/stdout a.c
char* strcpy (char*, const char*);

void sink (void*);

void f (__PTRDIFF_TYPE__ i)
{
  char a[8] = "012";

  if (i < __PTRDIFF_MAX__ - 2 || __PTRDIFF_MAX__ - 1 < i)
    i = __PTRDIFF_MAX__ - 2;

  strcpy (a + i, a);

  sink (a);
}
a.c: In function ‘f’:
a.c:12:3: warning: ‘strcpy’ offset [2147483645, 2147483646] is out of the
bounds [0, 8] of object ‘a’ with type ‘char[8]’ [-Warray-bounds]
   strcpy (a + i, a);
   ^~~~~~~~~~~~~~~~~
a.c:7:8: note: ‘a’ declared here
   char a[8] = "012";
        ^

;; Function f (f, funcdef_no=0, decl_uid=4214, cgraph_uid=0, symbol_order=0)

f (int i)
{
  char a[8];
  unsigned int i.0_1;
  unsigned int _2;
  char * _4;
  sizetype prephitmp_12;

  <bb 2> [local count: 1073741825]:
  a = "012";
  i.0_1 = (unsigned int) i_8(D);
  _2 = i.0_1 + 2147483651;
  if (_2 > 1)
    goto <bb 3>; [64.00%]
  else
    goto <bb 4>; [36.00%]

  <bb 3> [local count: 687194769]:

  <bb 4> [local count: 1073741825]:
  # prephitmp_12 = PHI <i.0_1(2), 2147483645(3)>
  _4 = &a + prephitmp_12;
  __builtin_memcpy (_4, &a, 4);
  sink (&a);
  a ={v} {CLOBBER};
  return;

}


a.c:12:3: warning: ‘__builtin_memcpy’ writing 4 bytes into a region of size 0
overflows the destination [-Wstringop-overflow=]
   strcpy (a + i, a);
   ^~~~~~~~~~~~~~~~~

Reply via email to