[PATCH][RFC] Add a subset of -Warray-bounds warnings to C/C++ front ends

Simon Baldwin simonb@google.com
Fri Apr 4 01:04:00 GMT 2008


Attached below is a modest patch to provide a subset of the -Warray-bounds
warnings from tree-vrp.c in the C and C++ front ends.  This permits the
compiler to warn about egregious array bounds violations in unoptimized
compilations or compilations that may use -fno-tree-vrp.  At present, array
bounds checking is only done on optimized compilations.

A side effect of copying these warnings up into the language frontends is
that warnings are now printed even if the array access is in dead or
inaccessible code.

The current array bounds tests are modified to account for this new checking,
and additionally there are two new tests for warnings from -O0 compilations,
one for C and one for C++.

Bootstrapped, and regression tested on i686 Linux for gcc and g++.

Thoughts?  Okay for trunk?


:ADDPATCH diagnostic:

gcc/ChangeLog
2008-04-03  Simon Baldwin <simonb@google.com>

	* c-typeck.c (build_array_ref): Added array bounds checking for
	bounded arrays indexed by constants.

gcc/cp/ChangeLog
2008-04-03  Simon Baldwin <simonb@google.com>

	* typeck.c (build_array_ref): Added array bounds checking for
	bounded arrays indexed by constants.

gcc/testsuite/ChangeLog
2008-04-03  Simon Baldwin <simonb@google.com>
  
	* testsuite/gcc.dg/Warray-bounds.c: Updated for frontend warnings.
	* testsuite/g++.dg/warn/Warray-bounds.c: Updated for frontend warnings.
	* testsuite/gcc.dg/Warray-bounds-noopt.c: New testcase.
	* testsuite/g++.dg/warn/Warray-bounds-noopt.c: New testcase.


Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 133772)
+++ gcc/doc/invoke.texi	(working copy)
@@ -2658,7 +2658,7 @@
 @option{-Wall} turns on the following warning flags:
 
 @gccoptlist{-Waddress   @gol
--Warray-bounds @r{(only with} @option{-O2}@r{)}  @gol
+-Warray-bounds @r{(some checks, but more complete with} @option{-O2}@r{)}  @gol
 -Wc++0x-compat  @gol
 -Wchar-subscripts  @gol
 -Wimplicit-int  @gol
@@ -3361,7 +3361,8 @@
 @item -Warray-bounds
 @opindex Wno-array-bounds
 @opindex Warray-bounds
-This option is only active when @option{-ftree-vrp} is active
+This option performs a subset of checks in unoptimized compilations, and
+stricter checking when @option{-ftree-vrp} is active
 (default for -O2 and above). It warns about subscripts to arrays
 that are always out of bounds. This warning is enabled by @option{-Wall}.
 
Index: gcc/testsuite/gcc.dg/Warray-bounds.c
===================================================================
--- gcc/testsuite/gcc.dg/Warray-bounds.c	(revision 133772)
+++ gcc/testsuite/gcc.dg/Warray-bounds.c	(working copy)
@@ -56,13 +56,13 @@
     g(&a[8]);
     g(&a[9]);
     g(&a[10]);
-    g(&a[11]);             /* { dg-warning "array subscript" "" { xfail *-*-* } } */
-    g(&a[-30]+10);             /* { dg-warning "array subscript" } */
-    g(&a[-30]+30);
+    g(&a[11]);             /* { dg-warning "array subscript" } */
+    g(&a[-30]+10);         /* { dg-warning "array subscript" } */
+    g(&a[-30]+30);         /* { dg-warning "array subscript" } */
 
     g(&b[10]);
     g(&c.c[10]);
-    g(&b[11]);             /* { dg-warning "array subscript" "" { xfail *-*-* } } */
+    g(&b[11]);             /* { dg-warning "array subscript" } */
     g(&c.c[11]);           /* { dg-warning "array subscript" } */
 
     g(&a[0]);
@@ -71,11 +71,11 @@
 
     g(&a[-1]);             /* { dg-warning "array subscript" } */
     g(&b[-1]);             /* { dg-warning "array subscript" } */ 
-    h(sizeof a[-1]);
+    h(sizeof a[-1]);       /* { dg-warning "array subscript" } */
     h(sizeof a[10]);
-    h(sizeof b[-1]);
+    h(sizeof b[-1]);       /* { dg-warning "array subscript" } */
     h(sizeof b[10]);
-    h(sizeof c.c[-1]);
+    h(sizeof c.c[-1]);     /* { dg-warning "array subscript" } */
     h(sizeof c.c[10]);
 
     if (10 < 10)
@@ -83,11 +83,10 @@
     if (10 < 10)
        b[10] = 0;
     if (-1 >= 0)
-       c.c[-1] = 0;
+       c.c[-1] = 0;        /* { dg-warning "array subscript" } */
 
     for (i = 20; i < 30; ++i)
              a[i] = 1;       /* { dg-warning "array subscript" } */
 
     return a;
 }
-
Index: gcc/testsuite/g++.dg/warn/Warray-bounds.C
===================================================================
--- gcc/testsuite/g++.dg/warn/Warray-bounds.C	(revision 133772)
+++ gcc/testsuite/g++.dg/warn/Warray-bounds.C	(working copy)
@@ -57,12 +57,11 @@
     g(&a[9]);
     g(&a[10]);
     g(&a[11]);             /* { dg-warning "array subscript" } */
-    g(&a[-30]+10);             /* { dg-warning "array subscript" } */
-    g(&a[-30]+30);
+    g(&a[-30]+10);         /* { dg-warning "array subscript" } */
+    g(&a[-30]+30);         /* { dg-warning "array subscript" } */
 
     g(&b[10]);
     g(&c.c[10]);
-    g(&a[11]);             /* { dg-warning "array subscript" } */
     g(&b[11]);             /* { dg-warning "array subscript" } */
     g(&c.c[11]);           /* { dg-warning "array subscript" } */
 
@@ -72,11 +71,11 @@
 
     g(&a[-1]);             /* { dg-warning "array subscript" } */
     g(&b[-1]);             /* { dg-warning "array subscript" } */ 
-    h(sizeof a[-1]);
+    h(sizeof a[-1]);       /* { dg-warning "array subscript" } */
     h(sizeof a[10]);
-    h(sizeof b[-1]);
+    h(sizeof b[-1]);       /* { dg-warning "array subscript" } */
     h(sizeof b[10]);
-    h(sizeof c.c[-1]);
+    h(sizeof c.c[-1]);     /* { dg-warning "array subscript" } */
     h(sizeof c.c[10]);
 
     if (10 < 10)
@@ -84,8 +83,10 @@
     if (10 < 10)
        b[10] = 0;
     if (-1 >= 0)
-       c.c[-1] = 0;
+       c.c[-1] = 0;        /* { dg-warning "array subscript" } */
+
+    for (i = 20; i < 30; ++i)
+             a[i] = 1;       /* { dg-warning "array subscript" } */
 
     return a;
 }
-
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c	(revision 133772)
+++ gcc/cp/typeck.c	(working copy)
@@ -2554,7 +2554,8 @@
 
   if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE)
     {
-      tree rval, type;
+      bool has_warned_on_bounds_check = false;
+      tree rval, type, ref;
 
       warn_array_subscript_with_type_char (idx);
 
@@ -2571,6 +2572,48 @@
 	 pointer arithmetic.)  */
       idx = perform_integral_promotions (idx);
 
+      /* Warn about obvious array bounds errors for fixed size arrays that
+         are indexed by a constant.  This is a subset of similar checks in
+         tree-vrp.c; by doing this here we can get some level of checking
+         from non-optimized, non-vrp compilation.  */
+      if (TREE_CODE (idx) == INTEGER_CST && TYPE_DOMAIN (TREE_TYPE (array)))
+        {
+          const_tree max_index;
+
+          max_index = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (array)));
+          if (max_index && TREE_CODE (max_index) == INTEGER_CST
+              && tree_int_cst_lt (max_index, idx)
+              && !tree_int_cst_equal (idx, max_index)
+              /* Always allow off-by-one.  */
+              && !tree_int_cst_equal (int_const_binop (PLUS_EXPR,
+                                                       max_index,
+                                                       integer_one_node,
+                                                       0),
+                                      idx)
+              /* Accesses after the end of arrays of size 0 (gcc
+                 extension) and 1 are likely intentional ("struct
+                 hack").  */
+              && compare_tree_int (max_index, 1) > 0)
+            {
+              warning (OPT_Warray_bounds,
+                       "array subscript is above array bounds");
+              has_warned_on_bounds_check = true;
+            }
+          else
+            {
+              const_tree min_index;
+
+              min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (array)));
+              if (min_index && TREE_CODE (min_index) == INTEGER_CST
+                  && tree_int_cst_lt (idx, min_index))
+                {
+                  warning (OPT_Warray_bounds,
+                           "array subscript is below array bounds");
+                  has_warned_on_bounds_check = true;
+                }
+            }
+        }
+
       /* An array that is indexed by a non-constant
 	 cannot be stored in a register; we must be able to do
 	 address arithmetic on its address.
@@ -2621,7 +2664,12 @@
 	|= (CP_TYPE_VOLATILE_P (type) | TREE_SIDE_EFFECTS (array));
       TREE_THIS_VOLATILE (rval)
 	|= (CP_TYPE_VOLATILE_P (type) | TREE_THIS_VOLATILE (array));
-      return require_complete_type (fold_if_not_in_template (rval));
+      ref = require_complete_type (fold_if_not_in_template (rval));
+
+      /* Suppress bounds warning in tree-vrp.c if already warned here.  */
+      if (has_warned_on_bounds_check)
+        TREE_NO_WARNING (ref) = 1;
+      return ref;
     }
 
   {
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c	(revision 133772)
+++ gcc/c-typeck.c	(working copy)
@@ -2086,7 +2086,50 @@
 
   if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE)
     {
-      tree rval, type;
+      bool has_warned_on_bounds_check = false;
+      tree rval, type, ref;
+
+      /* Warn about obvious array bounds errors for fixed size arrays that
+         are indexed by a constant.  This is a subset of similar checks in
+         tree-vrp.c; by doing this here we can get some level of checking
+         from non-optimized, non-vrp compilation.  */
+      if (TREE_CODE (index) == INTEGER_CST && TYPE_DOMAIN (TREE_TYPE (array)))
+        {
+          const_tree max_index;
+
+          max_index = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (array)));
+          if (max_index && TREE_CODE (max_index) == INTEGER_CST
+              && tree_int_cst_lt (max_index, index)
+              && !tree_int_cst_equal (index, max_index)
+              /* Always allow off-by-one.  */
+              && !tree_int_cst_equal (int_const_binop (PLUS_EXPR,
+                                                       max_index,
+                                                       integer_one_node,
+                                                       0),
+                                      index)
+              /* Accesses after the end of arrays of size 0 (gcc
+                 extension) and 1 are likely intentional ("struct
+                 hack").  */
+              && compare_tree_int (max_index, 1) > 0)
+            {
+              warning (OPT_Warray_bounds,
+                       "array subscript is above array bounds");
+              has_warned_on_bounds_check = true;
+            }
+          else
+            {
+              const_tree min_index;
+
+              min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (array)));
+              if (min_index && TREE_CODE (min_index) == INTEGER_CST
+                  && tree_int_cst_lt (index, min_index))
+                {
+                  warning (OPT_Warray_bounds,
+                           "array subscript is below array bounds");
+                  has_warned_on_bounds_check = true;
+                }
+            }
+        }
 
       /* An array that is indexed by a non-constant
 	 cannot be stored in a register; we must be able to do
@@ -2139,7 +2182,12 @@
 	       in an inline function.
 	       Hope it doesn't break something else.  */
 	    | TREE_THIS_VOLATILE (array));
-      return require_complete_type (fold (rval));
+      ref = require_complete_type (fold (rval));
+
+      /* Suppress bounds warning in tree-vrp.c if already warned here.  */
+      if (has_warned_on_bounds_check)
+        TREE_NO_WARNING (ref) = 1;
+      return ref;
     }
   else
     {



More information about the Gcc-patches mailing list