This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] enhance -Warray-bounds to handle strings and excessive indices


On 10/18/2017 04:48 AM, Richard Biener wrote:
On Wed, Oct 18, 2017 at 5:34 AM, Martin Sebor <msebor@gmail.com> wrote:
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.

+      /* 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.  */

I believe handling those cases are somewhat academic, but ...

Thanks for the quick review!

I agree the SSIZE_MAX tests handle corner cases and there are
arguably more important gaps here to plug (e.g., VLAs).  Then
again, most bugs tend to lurk in corner cases of one kind or
another and these seemed like a good way for me to come up to
speed on the implementation before tackling those.  If you
have suggestions for which to dive into next I'm happy to take
them.

+      tree eltype = TREE_TYPE (ref);
+      tree eltsize = TYPE_SIZE_UNIT (eltype);

needs to use array_ref_element_size.  Note that this size can be
non-constant in which case you now ICE so you have to check
this is an INTEGER_CST.

Thanks.  I did reproduce a few ICEs due to VLAs.  I've fixed
the problems and added tests for them.  One-dimensional VLAs
are now handled the same way arrays of unknown bound are.
Handling them more intelligently (i.e., taking into account
the ranges their bounds are in) and especially handling
multidimensional VLAs will take some effort.


+      tree maxbound = TYPE_MAX_VALUE (ssizetype);

please don't use ssizetype - sizetype can be of different precision
than pointers (and thus objects).  size_type_node would come
close (maps to size_t), eventually ptrdiff_type_node is also
defined by all frontends.

Okay, I've changed it to sizetype (it would be nice if there
were a cleaner way of doing it rather than by bit-twiddling.)

ptrdiff_type would have been my first choice but it's only defined
by the C/C++ front ends and not available in the middle-end, so
the other warnings that consider object sizes deal with ssizetype
(e.g., -Walloc-size-larger-than, -Wstringop- overflow, and
-Wformat-overflow).

That said, I'm not sure I understand under what conditions
ssizetype is not the signed equivalent of sizetype.  Can you
clarify?

As an aside, at some point I would like to get away from a type
based limit in all these warnings and instead use one that can
be controlled by an option so that a user can impose a lower limit
on the maximum size of an object and have all size-related warnings
(and perhaps even optimizations) enforce it and benefit from it.

+      up_bound_p1 = fold_build2 (TRUNC_DIV_EXPR, ssizetype, maxbound, eltsize);
+

int_const_binop if you insist on using trees...

Sure.  (I think offset_int would be more convenient but the rest
of the function uses trees so I just stuck to those to avoid
converting things back and forth or disrupting more of the code
than I had to.)


+      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;

so this gives up on a.b[i].c.d[k] (ok, array_at_struct_end_p will be false).
simply not subtracting anyhing instead of returning would be conservatively
correct, no?  Likewise subtracting the offset of the array for all "previous"
variably indexed components with assuming the lowest value for the index.
But as above I think compensating for the offset of the array within the object
is academic ... ;)

I was going to say yes (it gives up) but on second thought I don't
think it does.  Only the major index can be unbounded and the code
does consider the size of the sub-array when checking the major
index.  So, IIUC, I think this works correctly as is (*).  What
doesn't work is VLAs but those are a separate problem.  Let me
know if I misunderstood your question.

+      else if (code == STRING_CST)
+       up_bound_p1 = build_int_cst (ssizetype, TREE_STRING_LENGTH (arg));

that one is more interesting -- why's the TYPE_DOMAIN of the STRING_CST lacking
a max value?  Iff we use build_string_literal it should have the proper type.

Good question!  STRING_CST does have a domain.  The problem is
that array_at_struct_end_p() returns true for STRING_CST.  I've
added the handling to the function and removed the block above
from the latest patch.

Martin

[*] This is diagnosed:

  struct C { char d[4]; };
  struct B { struct C c; };
  struct A { struct B b[7]; };

  int f (struct A a, unsigned i, unsigned k)
  {
    if (i < 7) i = 7;
    if (k < 4) k = 4;

    return a.b[i].c.d[k];
  }

warning: array subscript 4 is above array bounds of ‘char[4]’ [-Warray-bounds]
     return a.b[i].c.d[k];
            ~~~~~~~~~~^~~
warning: array subscript 7 is above array bounds of ‘struct B[7]’ [-Warray-bounds]
     return a.b[i].c.d[k];
            ~~~^~~

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.c (array_at_struct_end_p): Handle STRING_CST.
	* 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.
	* gcc.dg/Warray-bounds-22.c: New test.

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..c100ca8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Warray-bounds.c
@@ -0,0 +1,239 @@
+/* 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;
+
+extern ssize_t signed_value (void)
+{
+  extern volatile ssize_t signed_value_source;
+  return signed_value_source;
+}
+
+extern size_t unsigned_value (void)
+{
+  extern volatile size_t unsigned_value_source;
+  return unsigned_value_source;
+}
+
+ssize_t signed_range (ssize_t min, ssize_t max)
+{
+  ssize_t val = signed_value ();
+  return val < min || max < val ? min : val;
+}
+
+struct AX { int n; char ax[]; };
+
+struct A1 { int i; char a1[1]; };
+struct B { int i; struct A1 a1x[]; };
+
+void sink (int, ...);
+
+#define R(min, max) signed_range (min, max)
+#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" } */
+
+  ssize_t i = R (SSIZE_MIN, -1);
+  T (ax_7[i][0]);                         /* { dg-warning "array subscript -1 is below array bounds" } */
+
+  T (ax_7[R (SSIZE_MIN, 0)][0]);
+  T (ax_7[R (-1, 0)][0]);
+  T (ax_7[R (-1, 1)][0]);
+  T (ax_7[R (-1, 7)][0]);
+  T (ax_7[R (-1, SSIZE_MAX)][0]);
+
+  T (ax_7[R ( 1, SSIZE_MAX)][0]);
+  T (ax_7[R (SSIZE_MAX / 14 - 1, SSIZE_MAX)][0]);
+
+  i = R (SSIZE_MAX / 14, SSIZE_MAX);
+  T (ax_7[i][0]);                         /* { dg-warning "array subscript \[0-9\]+ is above array bounds" } */
+
+  T (ax_7[0][R (SSIZE_MIN, 0)]);
+  T (ax_7[0][R (-1, 0)]);
+  T (ax_7[0][R (-1, 1)]);
+  T (ax_7[0][R (-1, 7)]);
+  T (ax_7[0][R (-1, SSIZE_MAX)]);
+  T (ax_7[0][R (-1, SSIZE_MAX)]);
+
+  T (ax_7[0][R (1, SSIZE_MAX)]);
+  T (ax_7[0][R (7, SSIZE_MAX)]);          /* { dg-warning "array subscript 7 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 .(const )?char *\\\[1]" "string" { xfail lp64 } } */
+  T (""[SSIZE_MIN + 1]);                  /* { dg-warning "array subscript -\[0-9\]+ is below array bounds of .(const )?char *\\\[1]" "string" } */
+  T (""[-1]);                             /* { dg-warning "array subscript -1 is below array bounds of .(const )?char *\\\[1]" "string" } */
+  T (""[0]);
+  T (""[1]);                              /* { dg-warning "array subscript 1 is above array bounds of .(const )?char *\\\[1]" "string" } */
+  T ("0"[2]);                             /* { dg-warning "array subscript 2 is above array bounds of .(const )?char *\\\[2]" "string" } */
+  T ("012"[2]);
+  T ("012"[3]);
+  T ("012"[4]);                           /* { dg-warning "array subscript 4 is above array bounds of .(const )?char *\\\[4]" "string" } */
+  T ("0123"[SSIZE_MAX]);                  /* { dg-warning "array subscript \[0-9\]+ is above array bounds of .(const )?char *\\\[5]" "string" } */
+  T ("0123"[SIZE_MAX]);                   /* { dg-warning "array subscript \[0-9\]+ is above array bounds of .(const )?char *\\\[5]" "string" } */
+}
+
+void fb_strlen (struct B *p)
+{
+#define strlen __builtin_strlen
+
+  T (strlen (&p->a1x[0].a1[2]));          /* { dg-warning "array subscript \[0-9\]+ is above array bounds" "strlen" } */
+  T (strlen (p->a1x[0].a1 + 2));          /* { dg-warning "array subscript \[0-9\]+ is above array bounds" "strlen" { xfail *-*-* } } */
+}
+
+
+void f_vla (unsigned n)
+{
+  char vla[n];
+
+  T (vla[SSIZE_MIN]);                     /* { dg-warning "array subscript -\[0-9\]+ is below array bounds" "vla" } */
+  T (vla[-1]);                            /* { dg-warning "array subscript -1 is below array bounds" "vla" } */
+  T (vla[0]);
+  T (vla[1]);
+  T (vla[n - 1]);
+  /* It would be nice to diagnose this. */
+  T (vla[n]);                             /* { dg-warning "array subscript \[0-9\]+ is above array bounds" "bug 82608" { xfail *-*-*} } */
+  T (vla[SSIZE_MAX]);                     /* { dg-warning "array subscript \[0-9\]+ is above array bounds" "vla" } */
+}
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);
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-22.c b/gcc/testsuite/gcc.dg/Warray-bounds-22.c
new file mode 100644
index 0000000..ec6fc8b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-22.c
@@ -0,0 +1,62 @@
+/* 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))
+
+void test_vla (unsigned m, unsigned n)
+{
+  char vla1[m];
+
+  T (vla1[SSIZE_MIN]);                    /* { dg-warning "array subscript -\[0-9\]+ is below array bounds" "vla" } */
+  T (vla1[-1]);                           /* { dg-warning "array subscript -1 is below array bounds" "vla" } */
+  T (vla1[0]);
+  T (vla1[1]);
+  T (vla1[n - 1]);
+  /* It would be nice to diagnose this. */
+  T (vla1[n]);                            /* { dg-warning "array subscript \[0-9\]+ is above array bounds" "bug 82608" { xfail *-*-*} } */
+  T (vla1[SSIZE_MAX]);                    /* { dg-warning "array subscript \[0-9\]+ is above array bounds" "vla" } */
+
+  char vla2[m][n];
+
+  T (vla2[0][SSIZE_MIN]);                 /* { dg-warning "array subscript -\[0-9\]+ is below array bounds" "vla" } */
+  T (vla2[0][-1]);                        /* { dg-warning "array subscript -1 is below array bounds" "vla" } */
+  T (vla2[0][0]);
+  T (vla2[1][1]);
+  T (vla2[m - 1][n - 1]);
+  /* It would be nice to diagnose this. */
+  T (vla2[m][0]);                         /* { dg-warning "array subscript \[0-9\]+ is above array bounds" "bug 82608" { xfail *-*-*} } */
+  T (vla2[m + 1][0]);                    /* { dg-warning "array subscript \[0-9\]+ is above array bounds" "bug 82608" { xfail *-*-*} } */
+  T (vla2[0][n]);                         /* { dg-warning "array subscript \[0-9\]+ is above array bounds" "bug 82608" { xfail *-*-*} } */
+  T (vla2[0][n + 1]);                     /* { dg-warning "array subscript \[0-9\]+ is above array bounds" "bug 82608" { xfail *-*-*} } */
+  T (vla2[m][n]);                         /* { dg-warning "array subscript \[0-9\]+ is above array bounds" "bug 82608" { xfail *-*-*} } */
+  T (vla2[m + 1][n + 1]);                 /* { dg-warning "array subscript \[0-9\]+ is above array bounds" "bug 82608" { xfail *-*-*} } */
+
+  T (vla2[0][SSIZE_MAX]);                 /* { dg-warning "array subscript \[0-9\]+ is above array bounds" "vla" } */
+  T (vla2[SSIZE_MAX][0]);                 /* { dg-warning "array subscript \[0-9\]+ is above array bounds" "vla" { xfail *-*-* } } */
+  T (vla2[SSIZE_MAX][SSIZE_MAX]);         /* { dg-warning "array subscript \[0-9\]+ is above array bounds" "vla" } */
+
+  struct VLA { char vla[n]; } x;
+
+  T (x.vla[SSIZE_MIN]);                   /* { dg-warning "array subscript -\[0-9\]+ is below array bounds" "vla" } */
+  T (x.vla[-1]);                          /* { dg-warning "array subscript -1 is below array bounds" "vla" } */
+  T (x.vla[0]);
+  T (x.vla[1]);
+  T (x.vla[n - 1]);
+  T (x.vla[SSIZE_MAX]);                   /* { dg-warning "array subscript \[0-9\]+ is above array bounds" "vla" } */
+}
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 2c86b8e..7330e8a 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,59 @@ 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;
+      || TREE_CODE (up_bound) != INTEGER_CST
+      || (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 eltsize = array_ref_element_size (ref);
+
+      /* FIXME: Handle VLAs.  */
+      if (TREE_CODE (eltsize) != INTEGER_CST)
+	return;
 
-  /* 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;
+      tree maxbound
+	= build_int_cst (sizetype, ~(1LLU << (TYPE_PRECISION (sizetype) - 1)));
+
+      up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, 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))
+	    {
+	      tree size = TYPE_SIZE_UNIT (TREE_TYPE (base));
+	      if (TREE_CODE (size) == INTEGER_CST)
+		up_bound_p1 = int_const_binop (MINUS_EXPR, up_bound_p1, size);
+	    }
+	  else
+	    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 +6753,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 +6770,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 +6784,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 +6840,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 +6854,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/tree.c b/gcc/tree.c
index cd77f08..4cf5f66 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -12515,6 +12515,9 @@ array_at_struct_end_p (tree ref)
   else
     return false;
 
+  if (TREE_CODE (ref) == STRING_CST)
+    return false;
+
   while (handled_component_p (ref))
     {
       /* If the reference chain contains a component reference to a

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]