public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c/106762] New: incorrect array bounds warning (-Warray-bounds) at -O2 on memset()
@ 2022-08-28 12:27 para at tampabay dot rr.com
  2022-08-29  8:34 ` [Bug c/106762] " rguenth at gcc dot gnu.org
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: para at tampabay dot rr.com @ 2022-08-28 12:27 UTC (permalink / raw)
  To: gcc-bugs

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

            Bug ID: 106762
           Summary: incorrect array bounds warning (-Warray-bounds) at -O2
                    on memset()
           Product: gcc
           Version: 11.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: para at tampabay dot rr.com
  Target Milestone: ---

Created attachment 53517
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=53517&action=edit
Minimized test case to reproduce the issue

This bug also affects GCC 12.0.1.

I have an inline function in a header file that does an array lookup, returning
NULL if the index given is out of bounds in the array. The result is passed to
another function to reset the structure. At -O2 this produces the following
warning:

bug.c:29:2: warning: ‘memset’ offset [0, 7] is out of the bounds [0, 0]
[-Warray-bounds]
   29 |  memset(&obj->field1, 0xff, sizeof(obj->field1));
      |  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This does not happen at -O0 or -O1. It appears that some part of the compiler
is incorrectly concluding that `obj` must be NULL. For now I am suppressing the
warning by assigning a structure field before calling memset() to hint that the
memset() is only reachable if the pointer is non-NULL.

One of the necessary conditions for reproducing this bug is curiously that the
field being memset() cannot be the first in the structure.

In the attached code that reproduces the issue I am setting the array index
`idx` to 0. The original code used a loop `for(idx = 0; idx < ary->objcnt;
idx++)` such that the else case cannot be hit.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Bug c/106762] incorrect array bounds warning (-Warray-bounds) at -O2 on memset()
  2022-08-28 12:27 [Bug c/106762] New: incorrect array bounds warning (-Warray-bounds) at -O2 on memset() para at tampabay dot rr.com
@ 2022-08-29  8:34 ` rguenth at gcc dot gnu.org
  2022-09-04 21:32 ` para at tampabay dot rr.com
  2022-09-04 23:00 ` para at tampabay dot rr.com
  2 siblings, 0 replies; 4+ messages in thread
From: rguenth at gcc dot gnu.org @ 2022-08-29  8:34 UTC (permalink / raw)
  To: gcc-bugs

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

Richard Biener <rguenth at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |WAITING
   Last reconfirmed|                            |2022-08-29
     Ever confirmed|0                           |1

--- Comment #1 from Richard Biener <rguenth at gcc dot gnu.org> ---
GCC diagnoses

(gdb) p debug_gimple_stmt (call)
# .MEM_11 = VDEF <.MEM_5(D)>
memset (8B, 255, 8);

which it carefully isolated:

<bb 2> [local count: 1073741824]:
_1 = ary_6(D)->objcnt;
if (_1 != 0)
  goto <bb 3>; [100.00%]
else
  goto <bb 4>; [0.00%]

<bb 3> [local count: 536870913]:
_2 = ary_6(D)->objary;
_3 = &_2->field1;
memset (_3, 255, 8);
_2->field0 = 0;
return;

<bb 4> [count: 0]:
memset (8B, 255, 8);
MEM[(struct obj_t *)0B].field0 ={v} 0;
__builtin_trap ();

that is, your code, if ary->objcnt == 0, calls memset (&NULL->field1, 0xff, 8).

But maybe you over-reduced the testcase?  If not then GCC is certainly
correct here and your code is bogus.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Bug c/106762] incorrect array bounds warning (-Warray-bounds) at -O2 on memset()
  2022-08-28 12:27 [Bug c/106762] New: incorrect array bounds warning (-Warray-bounds) at -O2 on memset() para at tampabay dot rr.com
  2022-08-29  8:34 ` [Bug c/106762] " rguenth at gcc dot gnu.org
@ 2022-09-04 21:32 ` para at tampabay dot rr.com
  2022-09-04 23:00 ` para at tampabay dot rr.com
  2 siblings, 0 replies; 4+ messages in thread
From: para at tampabay dot rr.com @ 2022-09-04 21:32 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #2 from Matt Taylor <para at tampabay dot rr.com> ---
Yes, the test case is immensely reduced from the original code. However, there
are still three problems. First, the warning fails to note that the array
bounds _could_ be [0,0] and implies that they are _always_ [0,0]. This was
confusing. Second, `memset` triggers the warning, but field assignment does
not. This is inconsistent. Third, if the order of the fields is rearranged,
then the warning is suppressed. It seems that it is permitting 1 byte to be
written to NULL and only fails for 2 or more bytes. Granted, it is unlikely
that someone would memset a single byte.

The original code was significantly more complicated than what I attached. The
most important piece of context that I omitted is that the 4 lines doing the
lookup are actually in an inline function. Our code looks more like this:
    struct obj_t* obj = lookup(ary, idx);
    memset(&obj->field1, 0xff, sizeof(obj->field1));
It is a half dozen different functions that have been inlined together, and
where the warning is generated it isn't at all clear that the bounds are [0,0]
because of an error check in another function that becomes dead code after
inlining. This actually happens in the body of a loop where `idx` increments
from 0 to `ary->objcnt`. Reintroducing the loop suppresses the warning in the
code that I attached, but I will work to reproduce the warning from a loop
body.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Bug c/106762] incorrect array bounds warning (-Warray-bounds) at -O2 on memset()
  2022-08-28 12:27 [Bug c/106762] New: incorrect array bounds warning (-Warray-bounds) at -O2 on memset() para at tampabay dot rr.com
  2022-08-29  8:34 ` [Bug c/106762] " rguenth at gcc dot gnu.org
  2022-09-04 21:32 ` para at tampabay dot rr.com
@ 2022-09-04 23:00 ` para at tampabay dot rr.com
  2 siblings, 0 replies; 4+ messages in thread
From: para at tampabay dot rr.com @ 2022-09-04 23:00 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #3 from Matt Taylor <para at tampabay dot rr.com> ---
Actually one thing that I said before does not make sense. I said that the
analysis seems to allow a 1 byte write to NULL but not 2 or more. However, the
warning does not trigger if the offset of the field in the structure is zero
despite the fact that it's writing 8 bytes and claims to have bounds of [0,0].
I haven't looked into this further, but perhaps it's only checking the initial
offset and ignoring the size?

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-09-04 23:00 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-28 12:27 [Bug c/106762] New: incorrect array bounds warning (-Warray-bounds) at -O2 on memset() para at tampabay dot rr.com
2022-08-29  8:34 ` [Bug c/106762] " rguenth at gcc dot gnu.org
2022-09-04 21:32 ` para at tampabay dot rr.com
2022-09-04 23:00 ` para at tampabay dot rr.com

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).