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 <uec...@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;