Bug 82608

Summary: missing -Warray-bounds on an out-of-bounds VLA index
Product: gcc Reporter: Martin Sebor <msebor>
Component: tree-optimizationAssignee: Martin Sebor <msebor>
Status: ASSIGNED ---    
Severity: normal Keywords: diagnostic
Priority: P3    
Version: 8.0   
Target Milestone: ---   
See Also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50584
Host: Target:
Build: Known to work:
Known to fail: 10.1.0, 11.0, 8.4.0, 9.3.0 Last reconfirmed: 2020-06-10 00:00:00
Bug Depends on:    
Bug Blocks: 56456    

Description Martin Sebor 2017-10-18 17:11:31 UTC
GCC doesn't diagnose out-of-bounds indices into VLAs even in cases where it could.  For instance, in the program below the upper bound of the VLA is at most 32 while the index is greater.  This information is available in the VRP pass and so it should be possible to detect this bug.

$ cat a.c && gcc -O2 -S -Wall -Warray-bounds -Wextra a.c
void sink (void*);

int f (unsigned n)
{
  if (n < 1 || n > 32)
    n = 32;

  char vla[n];

  sink (vla);

  return vla[97];   // missing -Warray-bounds
}
Comment 1 Martin Sebor 2019-03-11 19:01:29 UTC
A few more test cases:

$ cat z.c && gcc -O2 -S -Wall z.c
int idx_negative (void)
{ 
  int n = 4;
  char a[n];
  return a[-99];             // -Warray-bounds (since GCC 8)
}

int idx_cst_too_big (void)
{
  int n = 4;
  char a[n];
  return a[n + 1];           // missing _Warray-bounds
}

int idx_out_of_type_bounds (unsigned char n)
{
  char a[n];
  return a[__INT_MAX__];     // missing -Warray-bounds
}

int idx_var_too_big (int n)
{ 
  char a[n];
  return a[n + 1];           // missing -Warray-bounds
}

z.c: In function ‘idx_negative’:
z.c:5:11: warning: array subscript -99 is below array bounds of ‘char[<U4ea0> + 1]’ [-Warray-bounds]
    5 |   return a[-99];             // _Warray-bounds (since GCC 8)
      |          ~^~~~~
Comment 2 Martin Sebor 2019-11-05 17:06:05 UTC
Author: msebor
Date: Tue Nov  5 17:05:33 2019
New Revision: 277854

URL: https://gcc.gnu.org/viewcvs?rev=277854&root=gcc&view=rev
Log:
PR middle-end/92333 - missing variable name referencing VLA in warnings
PR middle-end/82608 - missing -Warray-bounds on an out-of-bounds VLA index

gcc/testsuite/ChangeLog:

	PR middle-end/92333
	PR middle-end/82608
	* gcc.dg/Warray-bounds-51.c: New test.

gcc/ChangeLog:

	PR middle-end/92333
	PR middle-end/82608
	* tree-vrp.c (vrp_prop::check_array_ref): Handle VLAs with constant
	size.
	* tree-ssa-ccp.c (fold_builtin_alloca_with_align): Use a meaninful
	name and location for a temporary variable.


Added:
    trunk/gcc/testsuite/gcc.dg/Warray-bounds-51.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/tree-ssa-ccp.c
    trunk/gcc/tree-vrp.c
Comment 3 Martin Sebor 2019-11-05 17:09:48 UTC
A partial fix (https://gcc.gnu.org/ml/gcc-patches/2019-11/msg00179.html) committed in r277854.  Out-of-bounds indices into VLAs with Non-constant sizes are not handled yet.
Comment 4 Martin Sebor 2020-06-10 17:53:42 UTC
GCC 11 issues -Wuninitialized for all accesses but only because the test case isn't careful enough to initialize the arrays before using them:

$ gcc -O2 -S -Wall -Wextra pr82608.c
pr82608.c: In function ‘idx_negative’:
pr82608.c:18:11: warning: ‘*(<unknown>)[-99]’ is used uninitialized [-Wuninitialized]
   18 |   return a[-99];             // -Warray-bounds (since GCC 8)
      |          ~^~~~~
pr82608.c: In function ‘idx_cst_too_big’:
pr82608.c:25:11: warning: ‘*(<unknown>)[<unknown>]’ is used uninitialized [-Wuninitialized]
   25 |   return a[n + 1];           // missing _Warray-bounds
      |          ~^~~~~~~
pr82608.c: In function ‘idx_out_of_type_bounds’:
pr82608.c:31:11: warning: ‘*(<unknown>)[2147483647]’ is used uninitialized [-Wuninitialized]
   31 |   return a[__INT_MAX__];     // missing -Warray-bounds
      |          ~^~~~~~~~~~~~~
pr82608.c: In function ‘idx_var_too_big’:
pr82608.c:37:11: warning: ‘*(<unknown>)[<unknown>]’ is used uninitialized [-Wuninitialized]
   37 |   return a[n + 1];           // missing -Warray-bounds
      |          ~^~~~~~~


With -Wno-uninitialized or with the arrays initialized GCC still doesn't detect all the out-of-bounds accesses:

$ cat pr82608.c && gcc -O2 -S -Wall -Wextra pr82608.c
void sink (void*);

int f (unsigned n)
{
  if (n < 1 || n > 32)
    n = 32;

  char vla[n];
  sink (vla);
  return vla[97];            // missing -Warray-bounds
}
int idx_negative (void)
{ 
  int n = 4;
  char a[n];
  sink (a);
  return a[-99];             // -Warray-bounds (since GCC 8)
}

int idx_cst_too_big (void)
{
  int n = 4;
  char a[n];
  sink (a);
  return a[n + 1];           // missing _Warray-bounds
}

int idx_out_of_type_bounds (unsigned char n)
{
  char a[n];
  sink (a);
  return a[__INT_MAX__];     // missing -Warray-bounds
}

int idx_var_too_big (int n)
{ 
  char a[n];
  sink (a);
  return a[n + 1];           // missing -Warray-bounds
}
pr82608.c: In function ‘idx_negative’:
pr82608.c:17:11: warning: array subscript -99 is below array bounds of ‘char[<U3750> + 1]’ [-Warray-bounds]
   17 |   return a[-99];             // -Warray-bounds (since GCC 8)
      |          ~^~~~~
pr82608.c:15:8: note: while referencing ‘a.16’
   15 |   char a[n];
      |        ^
pr82608.c: In function ‘idx_cst_too_big’:
pr82608.c:25:11: warning: array subscript 5 is above array bounds of ‘char[<U3ea0> + 1]’ [-Warray-bounds]
   25 |   return a[n + 1];           // missing _Warray-bounds
      |          ~^~~~~~~
pr82608.c:23:8: note: while referencing ‘a.18’
   23 |   char a[n];
      |        ^
Comment 5 Martin Sebor 2020-06-10 17:55:36 UTC
I'm working a fix for GCC 11 (it handles pr50584 as well).
Comment 6 CVS Commits 2020-09-19 23:57:40 UTC
The master branch has been updated by Martin Sebor <msebor@gcc.gnu.org>:

https://gcc.gnu.org/g:3f9a497d1b0dd9da87908a11b59bf364ad40ddca

commit r11-3306-g3f9a497d1b0dd9da87908a11b59bf364ad40ddca
Author: Martin Sebor <msebor@redhat.com>
Date:   Sat Sep 19 17:47:29 2020 -0600

    Extend -Warray-bounds to detect out-of-bounds accesses to array parameters.
    
    gcc/ChangeLog:
    
            PR middle-end/82608
            PR middle-end/94195
            PR c/50584
            PR middle-end/84051
            * gimple-array-bounds.cc (get_base_decl): New function.
            (get_ref_size): New function.
            (trailing_array): New function.
            (array_bounds_checker::check_array_ref): Call them.  Handle arrays
            declared in function parameters.
            (array_bounds_checker::check_mem_ref):  Same.  Handle references to
            dynamically allocated arrays.
    
    gcc/testsuite/ChangeLog:
    
            PR middle-end/82608
            PR middle-end/94195
            PR c/50584
            PR middle-end/84051
            * c-c++-common/Warray-bounds.c: Adjust.
            * gcc.dg/Wbuiltin-declaration-mismatch-9.c: Adjust.
            * gcc.dg/Warray-bounds-63.c: New test.
            * gcc.dg/Warray-bounds-64.c: New test.
            * gcc.dg/Warray-bounds-65.c: New test.
            * gcc.dg/Warray-bounds-66.c: New test.
            * gcc.dg/Warray-bounds-67.c: New test.
Comment 7 Martin Sebor 2020-09-20 00:11:40 UTC
Despite the enhancement the test case in comment #0 is still not diagnosed (the n argument has no range).
Comment 8 Jakub Jelinek 2021-04-27 11:38:01 UTC
GCC 11.1 has been released, retargeting bugs to GCC 11.2.