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

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

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |diagnostic
             Status|UNCONFIRMED                 |NEW
   Last reconfirmed|                            |2019-03-12
                 CC|                            |msebor at gcc dot gnu.org
          Component|c                           |tree-optimization
     Ever confirmed|0                           |1
      Known to fail|                            |8.3.0, 9.0

--- Comment #1 from Martin Sebor <msebor at gcc dot gnu.org> ---
Confirmed.  The warning is an unfortunate side-effect of an optimization
triggered by the 'if (c->data != __sb_slop)' test in the set0 function.  It
introduces a call to memcpy with __sb_slop as the destination.  The
intermediate representation of the code can be seen in the VRP dump with the
smaller test case below.  We're discussing ways to prevent this in the future
but the only way to avoid it for now that I can think of other than the
#pragma(*) is to either assert(**) h.data != __sb_slop just before calling
memcpy, or "hide" the conditional so it's not visible when compiling the
function that calls memcpy (e.g., by preventing set0 from being inlined via
attribute noinline), disable the warning for this code, or disable
_FORTIFY_SOURCE for this function by calling __builtin_memcpy directly.

[*] It's worth mentioning that #pragma GCC diagnostic doesn't work very well
for these late warnings when inlining is involved.
[**] An assert that would work without any cost is "if (h.data == __sb_slop)
__builtin_unreachable ();"

$ cat a.c && gcc -O2 -S -Wall -fdump-tree-vrp1=/dev/stdout a.c
char __sb_slop[1], buf[5];

void f (char *p)
{
  if (p != __sb_slop)
    p[0] = 0;

  __builtin___memcpy_chk (p, "abcd", 4, __builtin_object_size (p, 0));

  if (p != __sb_slop)
    p[0] = 0;

}


...
f (char * p)
{
  long unsigned int _15;
  long unsigned int _18;

  <bb 2> [local count: 1073741824]:
  if (p_4(D) != &__sb_slop)
    goto <bb 3>; [70.00%]
  else
    goto <bb 5>; [30.00%]                 ;; p_4(D) == &__sb_slop

  <bb 3> [local count: 751619278]:
  *p_4(D) = 0;
  _15 = __builtin_object_size (p_4(D), 0);
  __builtin_memcpy (p_4(D), "abcd", 4);
  *p_4(D) = 0;

  <bb 4> [local count: 1073741824]:
  return;

  <bb 5> [local count: 322122544]:
  _18 = __builtin_object_size (p_4(D), 0);
  __builtin_memcpy (p_4(D), "abcd", 4);   ;; p_4(D) == &__sb_slop
  goto <bb 4>; [100.00%]

}


a.c: In function ‘f’:
a.c:8:3: warning: ‘__builtin_memcpy’ forming offset [2, 4] is out of the bounds
[0, 1] of object ‘__sb_slop’ with type ‘char[1]’ [-Warray-bounds]
    8 |   __builtin___memcpy_chk (p, "abcd", 4, __builtin_object_size (p, 0));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
a.c:1:6: note: ‘__sb_slop’ declared here
    1 | char __sb_slop[1], buf[5];
      |      ^~~~~~~~~

Reply via email to