While testing my latest -Wrestrict changes I noticed a number of opportunities to improve the -Warray-bounds warning. Attached is a patch that implements a solution for the following subset of these:
PR tree-optimization/82596 - missing -Warray-bounds on an out-of bounds index into string literal PR tree-optimization/82588 - missing -Warray-bounds on an excessively large index PR tree-optimization/82583 - missing -Warray-bounds on out-of-bounds inner indices The patch also adds more detail to the -Warray-bounds diagnostics to make it easier to see the cause of the problem. Richard, since the changes touch tree-vrp.c, I look in particular for your comments. Thanks Martin
PR tree-optimization/82596 - missing -Warray-bounds on an out-of-bounds index into string literal PR tree-optimization/82588 - missing -Warray-bounds on a excessively large index PR tree-optimization/82583 - missing -Warray-bounds on out-of-bounds inner indic gcc/ChangeLog: PR tree-optimization/82596 PR tree-optimization/82588 PR tree-optimization/82583 * tree-vrp.c (check_array_ref): Handle flexible array members, string literals, and inner indices. (search_for_addr_array): Add detail to diagnostics. gcc/testsuite/ChangeLog: PR tree-optimization/82596 PR tree-optimization/82588 PR tree-optimization/82583 * c-c++-common/Warray-bounds.c: New test. * gcc.dg/Warray-bounds-11.c: Adjust. diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 2c86b8e..88cce15 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see #include "gimple-iterator.h" #include "gimple-walk.h" #include "tree-cfg.h" +#include "tree-dfa.h" #include "tree-ssa-loop-manip.h" #include "tree-ssa-loop-niter.h" #include "tree-ssa-loop.h" @@ -64,6 +65,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-cfgcleanup.h" #include "stringpool.h" #include "attribs.h" +#include "builtins.h" #define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL } @@ -6675,26 +6677,51 @@ check_array_ref (location_t location, tree ref, bool ignore_off_by_one) low_sub = up_sub = TREE_OPERAND (ref, 1); up_bound = array_ref_up_bound (ref); - /* Can not check flexible arrays. */ if (!up_bound - || TREE_CODE (up_bound) != INTEGER_CST) - return; + || (warn_array_bounds < 2 + && array_at_struct_end_p (ref))) + { + /* Accesses to trailing arrays via pointers may access storage + beyond the types array bounds. For such arrays, or for flexible + array members as well as for other arrays of an unknown size, + replace the upper bound with a more permissive one that assumes + the size of the largest object is SSIZE_MAX. */ + tree eltype = TREE_TYPE (ref); + tree eltsize = TYPE_SIZE_UNIT (eltype); + tree maxbound = TYPE_MAX_VALUE (ssizetype); + up_bound_p1 = fold_build2 (TRUNC_DIV_EXPR, ssizetype, maxbound, eltsize); + + tree arg = TREE_OPERAND (ref, 0); + tree_code code = TREE_CODE (arg); + if (code == COMPONENT_REF) + { + HOST_WIDE_INT off; + if (tree base = get_addr_base_and_unit_offset (ref, &off)) + up_bound_p1 = fold_build2 (MINUS_EXPR, ssizetype, up_bound_p1, + TYPE_SIZE_UNIT (TREE_TYPE (base))); + else + return; + } + else if (code == STRING_CST) + up_bound_p1 = build_int_cst (ssizetype, TREE_STRING_LENGTH (arg)); - /* Accesses to trailing arrays via pointers may access storage - beyond the types array bounds. */ - if (warn_array_bounds < 2 - && array_at_struct_end_p (ref)) - return; + up_bound = int_const_binop (MINUS_EXPR, up_bound_p1, + build_int_cst (ssizetype, 1)); + } + else + up_bound_p1 = int_const_binop (PLUS_EXPR, up_bound, + build_int_cst (TREE_TYPE (up_bound), 1)); low_bound = array_ref_low_bound (ref); - up_bound_p1 = int_const_binop (PLUS_EXPR, up_bound, - build_int_cst (TREE_TYPE (up_bound), 1)); + + tree artype = TREE_TYPE (TREE_OPERAND (ref, 0)); /* Empty array. */ if (tree_int_cst_equal (low_bound, up_bound_p1)) { warning_at (location, OPT_Warray_bounds, - "array subscript is above array bounds"); + "array subscript %E is above array bounds of %qT", + low_bound, artype); TREE_NO_WARNING (ref) = 1; } @@ -6718,7 +6745,8 @@ check_array_ref (location_t location, tree ref, bool ignore_off_by_one) && tree_int_cst_le (low_sub, low_bound)) { warning_at (location, OPT_Warray_bounds, - "array subscript is outside array bounds"); + "array subscript [%E, %E] is outside array bounds of %qT", + low_sub, up_sub, artype); TREE_NO_WARNING (ref) = 1; } } @@ -6734,7 +6762,8 @@ check_array_ref (location_t location, tree ref, bool ignore_off_by_one) fprintf (dump_file, "\n"); } warning_at (location, OPT_Warray_bounds, - "array subscript is above array bounds"); + "array subscript %E is above array bounds of %qT", + up_sub, artype); TREE_NO_WARNING (ref) = 1; } else if (TREE_CODE (low_sub) == INTEGER_CST @@ -6747,7 +6776,8 @@ check_array_ref (location_t location, tree ref, bool ignore_off_by_one) fprintf (dump_file, "\n"); } warning_at (location, OPT_Warray_bounds, - "array subscript is below array bounds"); + "array subscript %E is below array bounds of %qT", + low_sub, artype); TREE_NO_WARNING (ref) = 1; } } @@ -6802,7 +6832,8 @@ search_for_addr_array (tree t, location_t location) fprintf (dump_file, "\n"); } warning_at (location, OPT_Warray_bounds, - "array subscript is below array bounds"); + "array subscript %wi is below array bounds of %qT", + idx.to_shwi (), TREE_TYPE (tem)); TREE_NO_WARNING (t) = 1; } else if (idx > (wi::to_offset (up_bound) @@ -6815,7 +6846,8 @@ search_for_addr_array (tree t, location_t location) fprintf (dump_file, "\n"); } warning_at (location, OPT_Warray_bounds, - "array subscript is above array bounds"); + "array subscript %wu is above array bounds of %qT", + idx.to_uhwi (), TREE_TYPE (tem)); TREE_NO_WARNING (t) = 1; } } diff --git a/gcc/testsuite/c-c++-common/Warray-bounds.c b/gcc/testsuite/c-c++-common/Warray-bounds.c new file mode 100644 index 0000000..f94bd6e --- /dev/null +++ b/gcc/testsuite/c-c++-common/Warray-bounds.c @@ -0,0 +1,179 @@ +/* PR tree-optimization/82588 - missing -Warray-bounds on an excessively + large index + { dg-do compile } + { dg-options "-O2 -Warray-bounds -ftrack-macro-expansion=0" } */ + +#define SIZE_MAX __SIZE_MAX__ +#define SSIZE_MAX __PTRDIFF_MAX__ +#define SSIZE_MIN (-SSIZE_MAX - 1) + +typedef __PTRDIFF_TYPE__ ssize_t; +typedef __SIZE_TYPE__ size_t; + +struct AX { int n; char ax[]; }; + +struct A1 { int i; char a1[1]; }; +struct B { int i; struct A1 a1x[]; }; + +void sink (int, ...); + +#define T(expr) sink (0, (expr)) + +struct __attribute__ ((packed)) S16 { unsigned i: 16; }; + +void farr_char (void) +{ + extern char ac[]; + + T (ac[SSIZE_MIN]); /* { dg-warning "array subscript -\[0-9\]+ is below array bounds of .char *\\\[]." } */ + T (ac[-1]); /* { dg-warning "array subscript -1 is below array bounds" } */ + T (ac[0]); + + T (ac[SSIZE_MAX - 1]); + T (ac[SSIZE_MAX]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (ac[SSIZE_MAX + (size_t)1]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (ac[SIZE_MAX]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ +} + +void farr_s16 (void) +{ + extern struct S16 ax[]; + + T (ax[SSIZE_MIN]); /* { dg-warning "array subscript -\[0-9\]+ is below array bounds of .struct S16\\\[]." } */ + T (ax[-1]); /* { dg-warning "array subscript -1 is below array bounds" } */ + T (ax[0]); + + T (ax[SSIZE_MAX / 2 - 1]); + T (ax[SSIZE_MAX / 2]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (ax[SSIZE_MAX / 2 + (size_t)1]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (ax[SIZE_MAX]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ +} + +void farr_s16_7 (void) +{ + extern struct S16 ax_7[][7]; + + T (ax_7[0][SSIZE_MIN]); /* { dg-warning "array subscript -\[0-9\]+ is below array bounds of .struct S16 *\\\[7]." } */ + T (ax_7[0][-1]); /* { dg-warning "array subscript -1 is below array bounds" } */ + T (ax_7[0][0]); + T (ax_7[0][7]); /* { dg-warning "array subscript 7 is above array bounds of .struct S16 *\\\[7]." } */ + T (ax_7[0][8]); /* { dg-warning "array subscript 8 is above array bounds of .struct S16 *\\\[7]." } */ + + T (ax_7[0][SSIZE_MAX / 2]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (ax_7[0][SIZE_MAX]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + + T (ax_7[SSIZE_MIN][0]); /* { dg-warning "array subscript -\[0-9\]+ is below array bounds of .struct S16 *\\\[]\\\[7]." } */ + T (ax_7[-1][0]); /* { dg-warning "array subscript -1 is below array bounds" } */ + + T (ax_7[SSIZE_MAX / 2][0]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (ax_7[SIZE_MAX][0]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ +} + +void farr_x_5_7 (void) +{ + extern struct S16 a[][5][7]; + + T (a[0][0][-3]); /* { dg-warning "array subscript -3 is below array bounds of .struct S16 *\\\[7]." } */ + T (a[0][-2][0]); /* { dg-warning "array subscript -2 is below array bounds of .struct S16 *\\\[5]\\\[7]." } */ + T (a[-1][0][0]); /* { dg-warning "array subscript -1 is below array bounds of .struct S16 *\\\[]\\\[5]\\\[7]." } */ +} + + +void fax (struct AX *p) +{ + T (p->ax[SSIZE_MIN]); /* { dg-warning "array subscript -\[0-9\]+ is below array bounds" } */ + T (p->ax[-1]); /* { dg-warning "array subscript -1 is below array bounds" } */ + T (p->ax[0]); + T (p->ax[SSIZE_MAX - sizeof *p - 1]); + T (p->ax[SSIZE_MAX - sizeof *p]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (p->ax[SSIZE_MAX - sizeof *p + 1]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (p->ax[SIZE_MAX]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ +} + +void fa1 (struct A1 *p) +{ + T (p->a1[SSIZE_MIN]); /* { dg-warning "array subscript -\[0-9\]+ is below array bounds" } */ + T (p->a1[-1]); /* { dg-warning "array subscript -1 is below array bounds" } */ + T (p->a1[0]); + T (p->a1[9]); + T (p->a1[SSIZE_MAX - sizeof *p - 1]); + T (p->a1[SSIZE_MAX - sizeof *p]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (p->a1[SSIZE_MAX - sizeof *p + 1]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (p->a1[SIZE_MAX]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ +} + +void fb (struct B *p) +{ + T (p->a1x->a1[SSIZE_MIN]); /* { dg-warning "array subscript -\[0-9\]+ is below array bounds" } */ + T (p->a1x->a1[-1]); /* { dg-warning "array subscript -1 is below array bounds" } */ + T (p->a1x->a1[0]); + T (p->a1x->a1[9]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (p->a1x->a1[SSIZE_MAX - sizeof *p]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (p->a1x->a1[SSIZE_MAX - sizeof *p + 1]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (p->a1x->a1[SIZE_MAX]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + + T (p->a1x[1].a1[SSIZE_MIN]); /* { dg-warning "array subscript -\[0-9\]+ is below array bounds" } */ + T (p->a1x[1].a1[-1]); /* { dg-warning "array subscript -1 is below array bounds" } */ + T (p->a1x[1].a1[0]); + T (p->a1x[1].a1[9]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (p->a1x[1].a1[SSIZE_MAX - sizeof *p]);/* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (p->a1x[1].a1[SSIZE_MAX - sizeof *p + 1]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (p->a1x[1].a1[SIZE_MAX]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + + T (p->a1x[2].a1[SSIZE_MIN]); /* { dg-warning "array subscript -\[0-9\]+ is below array bounds" } */ + T (p->a1x[2].a1[-1]); /* { dg-warning "array subscript -1 is below array bounds" } */ + T (p->a1x[2].a1[0]); + T (p->a1x[2].a1[9]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (p->a1x[2].a1[SSIZE_MAX - sizeof *p]);/* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (p->a1x[2].a1[SSIZE_MAX - sizeof *p + 1]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (p->a1x[2].a1[SIZE_MAX]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + + T (p->a1x[3].a1[SSIZE_MIN]); /* { dg-warning "array subscript -\[0-9\]+ is below array bounds" } */ + T (p->a1x[3].a1[-1]); /* { dg-warning "array subscript -1 is below array bounds" } */ + T (p->a1x[3].a1[0]); + T (p->a1x[3].a1[9]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + + T (p->a1x[9].a1[0]); + + enum { MAX = SSIZE_MAX / sizeof *p->a1x - sizeof *p }; + + T (p->a1x[SSIZE_MIN].a1); /* { dg-warning "array subscript -\[0-9\]+ is below array bounds" } */ + T (p->a1x[-1].a1); /* { dg-warning "array subscript -1 is below array bounds" } */ + T (p->a1x[MAX].a1); + T (p->a1x[MAX + 2].a1); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + + T (p->a1x[SSIZE_MAX].a1); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (p->a1x[SIZE_MAX].a1); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + + T (p->a1x[SSIZE_MIN].a1[0]); /* { dg-warning "array subscript -\[0-9\]+ is below array bounds" } */ + T (p->a1x[-1].a1[0]) /* { dg-warning "array subscript -1 is below array bounds" } */; + T (p->a1x[MAX - 1].a1[0]); + T (p->a1x[MAX].a1[0]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (p->a1x[MAX + 1].a1[0]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + + T (p->a1x[SSIZE_MAX].a1[0]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ + T (p->a1x[SIZE_MAX].a1[0]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */ +} + +void f_cststring (int i) +{ + T (""[SSIZE_MIN]); /* { dg-warning "array subscript -\[0-9\]+ is below array bounds of .char *\\\[1]" "string" { xfail *-*-* } } */ + T (""[SSIZE_MIN + 1]); /* { dg-warning "array subscript -\[0-9\]+ is below array bounds of .char *\\\[1]" "string" } */ + T (""[-1]); /* { dg-warning "array subscript -1 is below array bounds of .char *\\\[1]" "string" } */ + T (""[0]); + T (""[1]); /* { dg-warning "array subscript 1 is above array bounds of .char *\\\[1]" "string" } */ + T ("0"[2]); /* { dg-warning "array subscript 2 is above array bounds of .char *\\\[2]" "string" } */ + T ("012"[2]); + T ("012"[3]); + T ("012"[4]); /* { dg-warning "array subscript 4 is above array bounds of .char *\\\[4]" "string" } */ + T ("0123"[SSIZE_MAX]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds of .char *\\\[5]" "string" } */ + T ("0123"[SIZE_MAX]); /* { dg-warning "array subscript \[0-9\]+ is above array bounds of .char *\\\[5]" "string" } */ +} + +void fb_strlen (struct B *p) +{ +#define strlen __builtin_strlen + + sink (strlen (&p->a1x[0].a1[2])); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" "strlen" } */ + sink (strlen (p->a1x[0].a1 + 2)); /* { dg-warning "array subscript \[0-9\]+ is above array bounds" "strlen" { xfail *-*-* } } */ +} diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-11.c b/gcc/testsuite/gcc.dg/Warray-bounds-11.c index 089fa00..c9fc461 100644 --- a/gcc/testsuite/gcc.dg/Warray-bounds-11.c +++ b/gcc/testsuite/gcc.dg/Warray-bounds-11.c @@ -57,19 +57,19 @@ struct h3b { void foo(int (*a)[3]) { - (*a)[4] = 1; /* { dg-warning "subscript is above array bound" } */ + (*a)[4] = 1; /* { dg-warning "subscript 4 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" } */ + a[1][4] = 1; /* { dg-warning "subscript 4 is above array bound" } */ int c[3] = { 0 }; - c[4] = 1; /* { dg-warning "subscript is above array bound" } */ + c[4] = 1; /* { dg-warning "subscript 4 is above array bound" } */ - e[4] = 1; /* { dg-warning "subscript is above array bound" } */ + e[4] = 1; /* { dg-warning "subscript 4 is above array bound" } */ struct f f; - f.f[4] = 1; /* { dg-warning "subscript is above array bound" } */ + f.f[4] = 1; /* { dg-warning "subscript 4 is above array bound" } */ struct h* h = malloc(sizeof(struct h) + 3 * sizeof(int)); struct h0* h0 = malloc(sizeof(struct h0) + 3 * sizeof(int)); @@ -78,15 +78,15 @@ void foo(int (*a)[3]) 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" } */ + h1->j[4] = 1; /* { dg-warning "subscript 4 is above array bound" } */ + h3->j[4] = 1; /* { dg-warning "subscript 4 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" } */ + h1b->j[4] = 1;; /* { dg-warning "subscript 4 is above array bound" } */ + h3b->j[4] = 1;; /* { dg-warning "subscript 4 is above array bound" } */ // make sure nothing gets optimized away bar(*a);