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

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

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |diagnostic
             Status|UNCONFIRMED                 |NEW
   Last reconfirmed|                            |2018-01-03
                 CC|                            |msebor at gcc dot gnu.org
          Component|c                           |tree-optimization
     Ever confirmed|0                           |1

--- Comment #1 from Martin Sebor <msebor at gcc dot gnu.org> ---
The reason for the warning is that the solution implemented for bug 83373 is
not effective at -O1 because the strlen pass (where it's been added) doesn't
run at that optimization level.  Warnings like -Warray-bounds and
-Wstringop-overflow rely on optimization, especially constant and range
propagation.  The latter doesn't run at -O1 either.  The better the optimizer
the higher the ratio of true positives to false negatives and false positives.

The warning in this case is also independent of inlining and can be reproduced
with the following simple test case:

char dst[20];
char src[10];

void my_strcpy (void)
{
  size_t len = strlen (src);
  if (len < sizeof src)
      memcpy (dst, src, len + 1);
  else
    {
      memcpy (dst, src, sizeof dst - 1);
      dst[sizeof dst - 1] = '\0';
  }
}

The IL the -Wstringop-overflow warning works with can be seen in the dump of
the -fdump-tree-optimized option (below).  At -O1, the second memcpy call
unconditionally accesses 19 bytes from the src array which triggers the
warning.  Because the strlen pass doesn't run, the warning has no way of
telling that the strlen(src) call cannot return a value greater than 19.

In this specific case it's possible to avoid the warning by moving the
strlen(array) optimization to run even at -O1 which seems like a good idea
regardless of the warning, so I'll confirm this bug on that basis.  There will
still be other cases where the full strlen pass is required and where these
kinds of issues will not be avoidable.

func2 ()
{
  size_t len;
  long unsigned int _4;

  <bb 2> [local count: 1073741825]:
  len_3 = strlen (&src);
  if (len_3 <= 19)
    goto <bb 3>; [50.00%]
  else
    goto <bb 4>; [50.00%]

  <bb 3> [local count: 536870912]:
  _4 = len_3 + 1;
  memcpy (&dest, &src, _4);
  goto <bb 5>; [100.00%]

  <bb 4> [local count: 536870912]:
  memcpy (&dest, &src, 19);
  MEM[(char *)&dest + 19B] = 0;

  <bb 5> [local count: 1073741825]:
  return;

}

Reply via email to