Bug 92110 - too many -Warray-bounds warnings for a loop buffer overflow
Summary: too many -Warray-bounds warnings for a loop buffer overflow
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 9.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks: Warray-bounds Wstringop-overflow
  Show dependency treegraph
 
Reported: 2019-10-15 19:27 UTC by Martin Sebor
Modified: 2020-05-14 19:24 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2019-10-16 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Sebor 2019-10-15 19:27:45 UTC
As mentioned in bug 92016, when GCC unrolls a loop that writes past the end of a buffer a separate instance of -Warray-bounds is issued for each iteration of the loop that writes past the end of the destination.  This can be seen in output for the test case below.  Likewise for -Wstringop-overflow when -Warray-bounds is disabled.  It would make the diagnostic output much less cluttered (and less overwhelming) if just a single warning was issued instead that descried the full extent of the buffer overflow (i.e., its size and offset from the beginning of the buffer).

$ cat c.c && gcc -S -O2 -Wall -Wextra -fdump-tree-strlen=/dev/stdout -fdump-tree-optimized=/dev/stdout c.c
static void f (char *p, unsigned n)
{
  while (n--)
    *p++ = 0;
}

void g (void*);

void h (void)
{
  char a[4];
  f (a, 8);
  g (a);
}
c.c: In function ‘h’:
c.c:4:10: warning: array subscript 4 is outside array bounds of ‘char[4]’ [-Warray-bounds]
    4 |     *p++ = 0;
      |     ~~~~~^~~
c.c:11:8: note: while referencing ‘a’
   11 |   char a[4];
      |        ^
c.c:4:10: warning: array subscript 5 is outside array bounds of ‘char[4]’ [-Warray-bounds]
    4 |     *p++ = 0;
      |     ~~~~~^~~
c.c:11:8: note: while referencing ‘a’
   11 |   char a[4];
      |        ^
c.c:4:10: warning: array subscript 6 is outside array bounds of ‘char[4]’ [-Warray-bounds]
    4 |     *p++ = 0;
      |     ~~~~~^~~
c.c:11:8: note: while referencing ‘a’
   11 |   char a[4];
      |        ^
c.c:4:10: warning: array subscript 7 is outside array bounds of ‘char[4]’ [-Warray-bounds]
    4 |     *p++ = 0;
      |     ~~~~~^~~
c.c:11:8: note: while referencing ‘a’
   11 |   char a[4];
      |        ^

;; Function h (h, funcdef_no=1, decl_uid=1939, cgraph_uid=2, symbol_order=1)

;; 2 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2
;; 2 succs { 1 }
h ()
{
  char * p;
  unsigned int n;
  char a[4];

  <bb 2> [local count: 118111601]:
  MEM[(char *)&a] = 0;
  MEM[(char *)&a + 1B] = 0;
  MEM[(char *)&a + 2B] = 0;
  MEM[(char *)&a + 3B] = 0;
  MEM[(char *)&a + 4B] = 0;
  MEM[(char *)&a + 5B] = 0;
  MEM[(char *)&a + 6B] = 0;
  MEM[(char *)&a + 7B] = 0;
  g (&a);
  a ={v} {CLOBBER};
  return;

}



;; Function h (h, funcdef_no=1, decl_uid=1939, cgraph_uid=2, symbol_order=1)

h ()
{
  char a[4];

  <bb 2> [local count: 118111601]:
  MEM <unsigned long> [(char *)&a] = 0;
  g (&a);
  a ={v} {CLOBBER};
  return;

}



$ gcc -S -O2 -Wall -Wextra -Wno-array-bounds c.c
static void f (char *p, unsigned n)
{
  while (n--)
    *p++ = 0;
}

void g (void*);

void h (void)
{
  char a[4];
  f (a, 8);
  g (a);
}
In function ‘f’,
    inlined from ‘h’ at c.c:12:3:
c.c:4:10: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
    4 |     *p++ = 0;
      |     ~~~~~^~~
c.c: In function ‘h’:
c.c:11:8: note: destination object declared here
   11 |   char a[4];
      |        ^
In function ‘f’,
    inlined from ‘h’ at c.c:12:3:
c.c:4:10: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
    4 |     *p++ = 0;
      |     ~~~~~^~~
c.c: In function ‘h’:
c.c:11:8: note: destination object declared here
   11 |   char a[4];
      |        ^
In function ‘f’,
    inlined from ‘h’ at c.c:12:3:
c.c:4:10: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
    4 |     *p++ = 0;
      |     ~~~~~^~~
c.c: In function ‘h’:
c.c:11:8: note: destination object declared here
   11 |   char a[4];
      |        ^
In function ‘f’,
    inlined from ‘h’ at c.c:12:3:
c.c:4:10: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
    4 |     *p++ = 0;
      |     ~~~~~^~~
c.c: In function ‘h’:
c.c:11:8: note: destination object declared here
   11 |   char a[4];
      |        ^
Comment 1 Richard Biener 2019-10-16 08:32:06 UTC
Confirmed.  This asks for TREE_NO_WARNING to be recorded per location.
Or rather record we already warned for -Warray-bounds for a specific location.
Or rather gathering all of them and emitting a combined warning like

c.c:4:10: warning: array subscripts 4 to 7 are outside array bounds of ‘char[4]’ [-Warray-bounds]
Comment 2 Martin Sebor 2019-10-16 15:17:41 UTC
The __builtin_warning patch implements the per-location solution (https://gcc.gnu.org/ml/gcc-patches/2019-10/msg01015.html) but I think the more aggregate approach would be more informative and so preferable.