Bug 86345 - Likely false warning with -Wstringop-overflow and memset
Summary: Likely false warning with -Wstringop-overflow and memset
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 9.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks: Wstringop-overflow
  Show dependency treegraph
 
Reported: 2018-06-28 13:30 UTC by Franz Sirl
Modified: 2022-10-23 00:24 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
testcase (406 bytes, text/plain)
2018-06-28 13:30 UTC, Franz Sirl
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Franz Sirl 2018-06-28 13:30:06 UTC
Created attachment 44335 [details]
testcase

The attached testcase warns like this with trunk@262215:

gcc-trunk -c -O2 -Wstringop-overflow test-stringop-overflow.c
test-stringop-overflow.c: In function 'func2':
test-stringop-overflow.c:56:3: warning: 'memset' specified size between 18446744071562067968 and 18446744073709551615 exceeds maximum object size 9223372036854775807 [-Wstringop-overflow=]
   memset ((buf), 0, (len));
   ^~~~~~~~~~~~~~~~~~~~~~~~

This is a relatively new regression on trunk (gcc-8-branch is fine). The code is quite sensitive to changes, so I didn't reduce it further.
Comment 1 Martin Sebor 2018-06-28 18:36:59 UTC
I can confirm the warning with the (possibly overly) reduced test case below but not really that it's a bug in the warning code.  In the reduced test case, memset() is called with a size that's either zero or in excess of PTRDIFF_MAX.  The call is diagnosed by design because the zero size is unlikely.

In the bigger test case, GCC (I think the jump threading pass) introduces a couple of earlier calls to memset that VRP substitutes constant arguments into and leaves the last call with the non-constant argument in the same ~[1, PTRDIFF_MAX] anti-range.  One solution would be to improve GCC to eliminate the last memcpy() call because it's either dead (zero size) or invalid.

In the meantime, changing the type of the argument to func2() to unsigned avoids the warning.  It's better to use unsigned variables to represent quantities that cannot be negative; that way the whole issue or excessively large results as a result of sign extension becomes moot.

$ cat c.c && gcc -O2 -S -Wall -fdump-tree-vrp=/dev/stdout c.c
void g (int *a, int n)
{
  if (n == 2)
    *a = 0;
  else if (n > 0)
    return;

  char b[8];
  __builtin_memset (b, 0, n);

  if (n == 2)
    return;

  __builtin_puts (b);
}

...
Value ranges after VRP:

...
_20: ~[1, 18446744071562067967]


g (int * a, int n)
{
  char b[8];
  long unsigned int _20;

  <bb 2> [local count: 1073741825]:
  if (n_5(D) == 2)
    goto <bb 3>; [34.00%]
  else
    goto <bb 4>; [66.00%]

  <bb 3> [local count: 365072220]:
  *a_7(D) = 0;
  goto <bb 5>; [100.00%]

  <bb 4> [local count: 708669604]:
  if (n_5(D) > 0)
    goto <bb 5>; [42.57%]
  else
    goto <bb 7>; [57.43%]

  <bb 5> [local count: 571979267]:
  b ={v} {CLOBBER};

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

  <bb 7> [local count: 501762557]:
  _20 = (long unsigned int) n_5(D);
  __builtin_memset (&b, 0, _20);
  __builtin_puts (&b);
  b ={v} {CLOBBER};
  goto <bb 6>; [100.00%]

}


c.c: In function ‘g’:
c.c:9:3: warning: ‘__builtin_memset’ specified size between 18446744071562067968 and 18446744073709551615 exceeds maximum object size 9223372036854775807 [-Wstringop-overflow=]
   __builtin_memset (b, 0, n);
   ^~~~~~~~~~~~~~~~~~~~~~~~~~
Comment 2 Martin Sebor 2018-06-28 19:11:08 UTC
As an aside, the warning first appeared with r260350 as a result of improvements to switch statement handling.
Comment 3 Andrew Pinski 2021-12-20 01:42:02 UTC
I can reproduce the warning in GCC 9.1.0-trunk with the reduced testcase but not with the original testcase.
Comment 4 Martin Liška 2022-01-31 16:32:03 UTC
The original test-case is fixed with r9-2639-gbb79aba479cf2288.