This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PING] Re: [PATCH] add option to emit more array bounds warnigs
- From: Martin Uecker <uecker at eecs dot berkeley dot edu>
- To: gcc Mailing List <gcc-patches at gcc dot gnu dot org>
- Cc: Jakub Jelinek <jakub at redhat dot com>, "Joseph S. Myers" <joseph at codesourcery dot com>, Richard Biener <rguenther at suse dot de>
- Date: Sun, 11 Jan 2015 20:36:10 -0800
- Subject: [PING] Re: [PATCH] add option to emit more array bounds warnigs
- Authentication-results: sourceware.org; auth=none
- References: <20141111221320 dot 24113af4 at lemur>
Please consider this patch. The additional warnings would be useful
IMHO, are also emitted by clang, and the change seems trivial.
Previous discussion about potential false positives:
https://gcc.gnu.org/ml/gcc/2014-11/msg00114.html
Tue, 11 Nov 2014 22:13:20 -0800
Martin Uecker <uecker@eecs.berkeley.edu>:
>
> Hi,
>
> this proposed patch adds an option "-Warray-bounds=" in addition to
> "-Warray-bound". "-Warray-bounds=1" corresponds to "-Warray-bound".
> For higher warning levels more warnings about optional accesses
> outside of arrays are emitted. For example, warnings for
> arrays accessed through pointers are now emitted:
>
> void foo(int (*a)[3])
> {
> (*a)[4] = 1;
> }
>
> Also warnings for arrays which are the last element of a struct
> are emitted, if it is not a flexible array member or does not use
> the zero size extensions.
>
> Because there is the risk of false positives, the higher warning
> level is not used by default.
>
>
> Martin
* gcc/tree-vrp.c (check_array_ref): Emit more warnings
for warn_array_bounds >= 2.
* gcc/testsuite/gcc.dg/Warray-bounds-11.c: New test-case.
* gcc/c-family/c.opt: New option -Warray-bounds=.
* gcc/common.opt: New option -Warray-bounds=.
* gcc/doc/invoke.texi: Document new option.
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 064c69e..e61fc56 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -279,6 +279,10 @@ Warray-bounds
LangEnabledBy(C ObjC C++ ObjC++,Wall)
; in common.opt
+Warray-bounds=
+LangEnabledBy(C ObjC C++ ObjC++,Wall,1,0)
+; in common.opt
+
Wassign-intercept
ObjC ObjC++ Var(warn_assign_intercept) Warning
Warn whenever an Objective-C assignment is being intercepted by the garbage collector
diff --git a/gcc/common.opt b/gcc/common.opt
index e104269..3d19875 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -529,6 +529,10 @@ Warray-bounds
Common Var(warn_array_bounds) Warning
Warn if an array is accessed out of bounds
+Warray-bounds=
+Common Joined RejectNegative UInteger Var(warn_array_bounds) Warning
+Warn if an array is accessed out of bounds
+
Wattributes
Common Var(warn_attributes) Init(1) Warning
Warn about inappropriate attribute usage
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index ed23f6f..f20cbf0 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -240,7 +240,7 @@ Objective-C and Objective-C++ Dialects}.
@gccoptlist{-fsyntax-only -fmax-errors=@var{n} -Wpedantic @gol
-pedantic-errors @gol
-w -Wextra -Wall -Waddress -Waggregate-return @gol
--Waggressive-loop-optimizations -Warray-bounds @gol
+-Waggressive-loop-optimizations -Warray-bounds -Warray-bounds=@var{n} @gol
-Wbool-compare @gol
-Wno-attributes -Wno-builtin-macro-redefined @gol
-Wc90-c99-compat -Wc99-c11-compat @gol
@@ -3382,7 +3382,7 @@ Options} and @ref{Objective-C and Objective-C++ Dialect Options}.
@option{-Wall} turns on the following warning flags:
@gccoptlist{-Waddress @gol
--Warray-bounds @r{(only with} @option{-O2}@r{)} @gol
+-Warray-bounds=1 @r{(only with} @option{-O2}@r{)} @gol
-Wc++11-compat -Wc++14-compat@gol
-Wchar-subscripts @gol
-Wenum-compare @r{(in C/ObjC; this is on by default in C++)} @gol
@@ -4296,12 +4296,26 @@ Warn about overriding virtual functions that are not marked with the override
keyword.
@item -Warray-bounds
+@itemx -Warray-bounds=@var{n}
@opindex Wno-array-bounds
@opindex Warray-bounds
This option is only active when @option{-ftree-vrp} is active
(default for @option{-O2} and above). It warns about subscripts to arrays
that are always out of bounds. This warning is enabled by @option{-Wall}.
+@table @gcctabopt
+@item -Warray-bounds=1
+This is the warning level of @option{-Warray-bounds} and is enabled
+by @option{-Wall}; higher levels are not, and must be explicitly requested.
+
+@item -Warray-bounds=2
+This warning level also warns about out of bounds access for
+arrays at the end of a struct and for arrays accessed through
+pointers. This warning level may give a larger number of
+false positives and is deactivated by default.
+@end table
+
+
@item -Wbool-compare
@opindex Wno-bool-compare
@opindex Wbool-compare
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-11.c b/gcc/testsuite/gcc.dg/Warray-bounds-11.c
new file mode 100644
index 0000000..2e68498
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-11.c
@@ -0,0 +1,96 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -Warray-bounds=2" } */
+
+extern void* malloc(unsigned long x);
+
+int e[3];
+
+struct f { int f[3]; };
+
+extern void bar(int v[]);
+
+struct h {
+
+ int i;
+ int j[];
+};
+
+struct h0 {
+
+ int i;
+ int j[0];
+};
+
+struct h0b {
+
+ int i;
+ int j[0];
+ int k;
+};
+
+struct h1 {
+
+ int i;
+ int j[1];
+};
+
+struct h1b {
+
+ int i;
+ int j[1];
+ int k;
+};
+
+struct h3 {
+
+ int i;
+ int j[3];
+};
+
+struct h3b {
+
+ int i;
+ int j[3];
+ int k;
+};
+
+void foo(int (*a)[3])
+{
+ (*a)[4] = 1; /* { dg-warning "subscript is above array bound" } */
+ a[0][0] = 1; // ok
+ a[1][0] = 1; // ok
+ a[1][4] = 1; /* { dg-warning "subscript is above array bound" } */
+
+ int c[3] = { 0 };
+
+ c[4] = 1; /* { dg-warning "subscript is above array bound" } */
+
+ e[4] = 1; /* { dg-warning "subscript is above array bound" } */
+
+ struct f f;
+ f.f[4] = 1; /* { dg-warning "subscript is above array bound" } */
+
+ struct h* h = malloc(sizeof(struct h) + 3 * sizeof(int));
+ struct h0* h0 = malloc(sizeof(struct h0) + 3 * sizeof(int));
+ struct h1* h1 = malloc(sizeof(struct h1) + 3 * sizeof(int));
+ struct h3* h3 = malloc(sizeof(struct h3));
+
+ h->j[4] = 1; // flexible array member
+ h0->j[4] = 1; // zero-sized array extension
+ h1->j[4] = 1; /* { dg-warning "subscript is above array bound" } */
+ h3->j[4] = 1; /* { dg-warning "subscript is above array bound" } */
+
+ struct h0b* h0b = malloc(sizeof(struct h) + 3 * sizeof(int));
+ struct h1b* h1b = malloc(sizeof(struct h1b) + 3 * sizeof(int));
+ struct h3b* h3b = malloc(sizeof(struct h3b));
+// h0b->j[4] = 1;
+ h1b->j[4] = 1;; /* { dg-warning "subscript is above array bound" } */
+ h3b->j[4] = 1;; /* { dg-warning "subscript is above array bound" } */
+
+ // make sure nothing gets optimized away
+ bar(*a);
+ bar(c);
+ bar(e);
+ bar(f.f);
+}
+
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index ae1da46..d20b627 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -6498,7 +6498,8 @@ check_array_ref (location_t location, tree ref, bool ignore_off_by_one)
/* Accesses to trailing arrays via pointers may access storage
beyond the types array bounds. */
base = get_base_address (ref);
- if (base && TREE_CODE (base) == MEM_REF)
+ if ((warn_array_bounds < 2)
+ && base && TREE_CODE (base) == MEM_REF)
{
tree cref, next = NULL_TREE;