PR tree-optimization/84047 - missing -Warray-bounds on an out-of-bounds index into...
authorMartin Sebor <msebor@redhat.com>
Thu, 19 Jul 2018 23:36:34 +0000 (23:36 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Thu, 19 Jul 2018 23:36:34 +0000 (17:36 -0600)
PR tree-optimization/84047 - missing -Warray-bounds on an out-of-bounds index into an array
PR tree-optimization/83776 - missing -Warray-bounds indexing past the end of a string literal

gcc/ChangeLog:

PR tree-optimization/84047
PR tree-optimization/83776
* tree-vrp.c (vrp_prop::check_mem_ref): New function.
(check_array_bounds): Call it.

gcc/testsuite/ChangeLog:

PR tree-optimization/83776
PR tree-optimization/84047
* gcc.dg/Warray-bounds-29.c: New test.
* gcc.dg/Warray-bounds-30.c: New test.
* gcc.dg/Warray-bounds-31.c: New test.
* gcc.dg/Warray-bounds-32.c: New test.

From-SVN: r262893

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/Warray-bounds-29.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Warray-bounds-30.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Warray-bounds-31.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Warray-bounds-32.c [new file with mode: 0644]
gcc/tree-vrp.c

index 264d051..09329f4 100644 (file)
@@ -1,5 +1,12 @@
 2018-07-19  Martin Sebor  <msebor@redhat.com>
 
+       PR tree-optimization/84047
+       PR tree-optimization/83776
+       * tree-vrp.c (vrp_prop::check_mem_ref): New function.
+       (check_array_bounds): Call it.
+
+2018-07-19  Martin Sebor  <msebor@redhat.com>
+
        * align.h (align_flags): Use member initialization.
 
 2018-07-19  David Malcolm  <dmalcolm@redhat.com>
index b8b309f..8eccef1 100644 (file)
@@ -1,3 +1,12 @@
+2018-07-19  Martin Sebor  <msebor@redhat.com>
+
+       PR tree-optimization/83776
+       PR tree-optimization/84047
+       * gcc.dg/Warray-bounds-29.c: New test.
+       * gcc.dg/Warray-bounds-30.c: New test.
+       * gcc.dg/Warray-bounds-31.c: New test.
+       * gcc.dg/Warray-bounds-32.c: New test.
+
 2018-07-19  Michael Collison  <michael.collison@arm.com>
            Richard Henderson <rth@redhat.com>
 
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-29.c b/gcc/testsuite/gcc.dg/Warray-bounds-29.c
new file mode 100644 (file)
index 0000000..72c5d1c
--- /dev/null
@@ -0,0 +1,150 @@
+/* PR tree-optimization/83776: missing -Warray-bounds indexing past the end
+   of a string literal
+   Test to exercise warnings for computations of otherwise in-bounds indices
+   into strings that temporarily exceed the bounds of the string.
+   { dg-do compile }
+   { dg-options "-O2 -Warray-bounds=2 -ftrack-macro-expansion=0" } */
+
+#include "range.h"
+
+#define MAX DIFF_MAX
+#define MIN DIFF_MIN
+
+typedef __WCHAR_TYPE__ wchar_t;
+
+void sink (int, ...);
+
+#define T(expr)   sink (0, expr)
+
+void test_narrow (void)
+{
+  int i = SR (1, 2);
+
+  const char *p0 = "12";
+  const char *p1 = p0 + i;    /* points at '2' or beyond */
+  const char *p2 = p1 + i;    /* points at '\0' or beyond */
+  const char *p3 = p2 + i;    /* points just past the end */
+  const char *p4 = p3 + i;    /* invalid */
+
+  T (p0[-1]);                 /* { dg-warning "array subscript \(-1|\[0-9\]+) is outside array bounds of .char\\\[3]." } */
+  T (p0[0]);
+  T (p0[1]);
+  T (p0[2]);
+  T (p0[3]);                  /* { dg-warning "array subscript 3 is outside array bounds of .char\\\[3]." } */
+
+  T (&p0[-1]);                /* { dg-warning "array subscript \(-1|\[0-9\]+) is \(above|below|outside\) array bounds of .char\\\[3]." } */
+  T (&p0[0]);
+  T (&p0[1]);
+  T (&p0[2]);
+  T (&p0[3]);
+  T (&p0[4]);                 /* { dg-warning "array subscript 4 is \(above|outside\) array bounds of .char\\\[3]." } */
+
+  T (p1[-3]);                 /* { dg-warning "array subscript \\\[-2, -1] is outside array bounds of .char\\\[3]." } */
+  T (p1[-2]);
+  T (p1[-1]);
+  T (p1[ 0]);
+  T (p1[ 1]);
+  T (p1[ 2]);                 /* { dg-warning "array subscript \\\[3, 4] is outside array bounds of .char\\\[3]." } */
+  T (p1[ 3]);                 /* { dg-warning "array subscript \\\[4, 5] is outside array bounds of .char\\\[3]." } */
+
+  T (&p1[-3]);                /* { dg-warning "array subscript \\\[-2, -1] is outside array bounds of .char\\\[3]." "bug" { xfail *-*-* } } */
+  T (&p1[-2]);
+  T (&p1[-1]);
+  T (&p1[ 0]);
+  T (&p1[ 1]);
+  T (&p1[ 2]);
+  T (&p1[ 3]);                /* { dg-warning "array subscript \\\[4, 6] is outside array bounds of .char\\\[3]." "bug" { xfail *-*-* } } */
+
+  T (p2[-4]);                 /* { dg-warning "intermediate array offset 4 is outside array bounds of .char\\\[3]." } */
+  T (p2[-3]);
+  T (p2[-2]);
+  T (p2[-1]);
+  T (p2[ 0]);
+
+  /* Even though the lower bound of p3's offsets is in bounds, in order
+     to subtract 4 from p3 and get a dereferenceable pointer its value
+     would have to be out-of-bounds.  */
+  T (p3[-4]);                 /* { dg-warning "intermediate array offset 4 is outside array bounds of .char\\\[3]." } */
+  T (p3[-3]);
+  T (p3[-2]);
+  T (p3[-1]);
+  T (p3[ 0]);                 /* { dg-warning "array subscript \\\[3, 6] is outside array bounds of .char\\\[3]." } */
+
+  T (p4[-4]);                 /* { dg-warning "intermediate array offset 4 is outside array bounds of .char\\\[3]." } */
+  T (p4[-3]);                 /* { dg-warning "intermediate array offset 4 is outside array bounds of .char\\\[3]." } */
+  T (p4[-2]);                 /* { dg-warning "intermediate array offset 4 is outside array bounds of .char\\\[3]." } */
+
+  /* The final subscripts below are invalid.  */
+  T (p4[-1]);                 /* { dg-warning "array subscript \\\[3, 7] is outside array bounds of .char\\\[3]." } */
+  T (p4[ 0]);                 /* { dg-warning "array subscript \\\[4, 8] is outside array bounds of .char\\\[3]." } */
+}
+
+
+void test_narrow_vflow (void)
+{
+  int i = SR (DIFF_MAX - 2, DIFF_MAX);
+  int j = SR (1, DIFF_MAX);
+
+  const char *p0 = "123";
+  const char *p1 = p0 + i;    /* points at '2' or beyond */
+  const char *p2 = p1 + i;    /* points at '\0' or beyond */
+  const char *p3 = p2 + i;    /* points just past the end */
+  const char *p4 = p3 + i;    /* invalid */
+}
+
+
+void test_wide (void)
+{
+  int i = SR (1, 2);
+
+  const wchar_t *p0 = L"123";
+  const wchar_t *p1 = p0 + i;    /* points at L'2' or beyond */
+  const wchar_t *p2 = p1 + i;    /* points at L'3' or beyond */
+  const wchar_t *p3 = p2 + i;    /* points at L'\0' or beyond */
+  const wchar_t *p4 = p3 + i;    /* points just past the end */
+  const wchar_t *p5 = p4 + i;    /* invalid */
+
+  T (p0[0]);
+  T (p0[1]);
+  T (p0[2]);
+  T (p0[3]);
+  T (p0[4]);                  /* { dg-warning "array subscript 4 is outside array bounds of .\[a-z \]+\\\[4]." } */
+
+  T (p1[-1]);
+  T (p1[ 0]);
+  T (p1[ 1]);
+  T (p1[ 2]);
+  T (p1[ 3]);                  /* { dg-warning "array subscript \\\[4, 5] is outside array bounds of .\[a-z \]+\\\[4]." } */
+
+  T (&p1[-1]);
+  T (&p1[ 0]);
+  T (&p1[ 1]);
+  T (&p1[ 2]);
+  T (&p1[ 3]);
+  T (&p1[ 4]);                 /* { dg-warning "array subscript \\\[5, 6] is outside array bounds of .\[a-z \]+\\\[4]." "bug" { xfail *-*-* } } */
+
+  T (p2[-5]);                 /* { dg-warning "array subscript \\\[-3, -1] is outside array bounds of .\[a-z \]+\\\[4]." } */
+  T (p2[-4]);
+  T (p2[-3]);
+  T (p2[-2]);
+  T (p2[-1]);
+  T (p2[ 0]);
+
+  /* Even though the lower bound of p3's offsets is in bounds, in order
+     to subtract 5 from p3 and get a dereferenceable pointer its value
+     would have to be out-of-bounds.  */
+  T (p3[-5]);                 /* { dg-warning "intermediate array offset 5 is outside array bounds of .\[a-z \]+\\\[4]." } */
+  T (p3[-4]);
+  T (p3[-3]);
+  T (p3[-2]);
+  T (p3[-1]);
+  T (p3[ 0]);
+  T (p3[ 1]);                 /* { dg-warning "array subscript \\\[4, 7] is outside array bounds of .\[a-z \]+\\\[4]." } */
+
+  T (p4[-5]);                 /* { dg-warning "intermediate array offset 5 is outside array bounds of .\[a-z \]+\\\[4]." } */
+  T (p4[-4]);
+  T (p4[-3]);
+  T (p4[-2]);
+  T (p4[-1]);
+  T (p4[ 0]);                 /* { dg-warning "array subscript \\\[4, 8] is outside array bounds of .\[a-z \]+\\\[4]." } */
+}
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-30.c b/gcc/testsuite/gcc.dg/Warray-bounds-30.c
new file mode 100644 (file)
index 0000000..ac7e9a6
--- /dev/null
@@ -0,0 +1,200 @@
+/* PR tree-optimization/84047 - missing -Warray-bounds on an out-of-bounds
+   index into an array
+   { dg-do compile }
+   { dg-options "-O2 -Warray-bounds=2 -ftrack-macro-expansion=0" } */
+
+#include "range.h"
+
+#define MAX DIFF_MAX
+#define MIN DIFF_MIN
+
+void sink (int, ...);
+
+#define T(...)   sink (0, __VA_ARGS__)
+
+void test_global_char_array (void)
+{
+  extern char gcar1[1];
+  char *p = gcar1;
+
+  T (p[MIN]);       /* { dg-warning "subscript -\[0-9\]+ is outside array bounds of .char\\\[1]." } */
+  T (p[-1]);        /* { dg-warning "subscript -1 is outside array bounds of .char\\\[1]." } */
+  T (p[0]);
+  T (p[1]);         /* { dg-warning "subscript 1 is outside array bounds of .char\\\[1]." } */
+  T (p[MAX]);       /* { dg-warning "subscript \[0-9\]+ is outside array bounds of .char\\\[1]." } */
+
+  T (&p[MIN]);      /* { dg-warning "subscript -\[0-9\]+ is \(below|outside\) array bounds of .char\\\[1]." } */
+  T (&p[-1]);       /* { dg-warning "subscript -1 is \(below|outside\) array bounds of .char\\\[1]." } */
+  T (&p[0]);
+  T (&p[1]);
+  T (&p[2]);        /* { dg-warning "subscript 2 is \(above|outside\) array bounds of .char\\\[1]." } */
+  T (&p[MAX]);      /* { dg-warning "subscript \[0-9\]+ is \(above|outside\) array bounds of .char\\\[1]." } */
+
+  extern char gcar3[3];
+  char *q = gcar3;
+
+  T (q[MIN]);       /* { dg-warning "subscript -\[0-9\]+ is outside array bounds of .char\\\[3]." } */
+  T (q[-1]);        /* { dg-warning "subscript -1 is outside array bounds of .char\\\[3]." } */
+  T (q[0]);
+  T (q[1]);
+  T (q[2]);
+  T (q[3]);         /* { dg-warning "subscript 3 is outside array bounds of .char\\\[3]." } */
+  T (q[MAX]);       /* { dg-warning "subscript \[0-9\]+ is outside array bounds of .char\\\[3]." } */
+
+  T (&q[MIN]);      /* { dg-warning "subscript -\[0-9\]+ is \(below|outside\) array bounds of .char\\\[3]." } */
+  T (&q[-1]);       /* { dg-warning "subscript -1 is \(below|outside\) array bounds of .char\\\[3]." } */
+  T (&q[0]);
+  T (&q[1]);
+  T (&q[2]);
+  T (&q[3]);
+  T (&q[4]);        /* { dg-warning "subscript 4 is \(above|outside\) array bounds of .char\\\[3]." } */
+  T (&q[MAX]);      /* { dg-warning "subscript \[0-9\]+ is \(above|outside\) array bounds of .char\\\[3]." } */
+}
+
+
+void test_global_int_array (void)
+{
+  /* Use smaller values to prevent false negatives due to undetected
+     integer overflow/wrapping.  */
+  ptrdiff_t min = MIN / sizeof (int);
+  ptrdiff_t max = MAX / sizeof (int);
+
+  extern int giar1[1];
+  extern int giar3[3];
+
+  int *p = giar1;
+
+  T (p[min]);       /* { dg-warning "subscript -\[0-9\]+ is outside array bounds of .int\\\[1]." } */
+  T (p[-1]);        /* { dg-warning "subscript -1 is outside array bounds of .int\\\[1]." } */
+  T (p[0]);
+  T (p[1]);         /* { dg-warning "subscript 1 is outside array bounds of .int\\\[1]." } */
+  T (p[max]);       /* { dg-warning "subscript \[0-9\]+ is outside array bounds of .int\\\[1]." } */
+
+  T (&p[min]);      /* { dg-warning "subscript -\[0-9\]+ is \(below|outside\) array bounds of .int\\\[1]." } */
+  T (&p[-1]);       /* { dg-warning "subscript -1 is \(below|outside\) array bounds of .int\\\[1]." } */
+  T (&p[0]);
+  T (&p[1]);
+  T (&p[2]);        /* { dg-warning "subscript 2 is \(above|outside\) array bounds of .int\\\[1]." } */
+  T (&p[max]);      /* { dg-warning "subscript \[0-9\]+ is \(above|outside\) array bounds of .int\\\[1]." } */
+
+  int *q = giar3;
+
+  T (q[min]);       /* { dg-warning "subscript -\[0-9\]+ is outside array bounds of .int\\\[3]." } */
+  T (q[-1]);        /* { dg-warning "subscript -1 is outside array bounds of .int\\\[3]." } */
+  T (q[0]);
+  T (q[1]);
+  T (q[2]);
+  T (q[3]);         /* { dg-warning "subscript 3 is outside array bounds of .int\\\[3]." } */
+  T (q[max]);       /* { dg-warning "subscript \[0-9\]+ is outside array bounds of .int\\\[3]." } */
+
+  T (&q[min]);      /* { dg-warning "subscript -\[0-9\]+ is \(below|outside\) array bounds of .int\\\[3]." } */
+  T (&q[-1]);       /* { dg-warning "subscript -1 is \(below|outside\) array bounds of .int\\\[3]." } */
+  T (&q[0]);
+  T (&q[1]);
+  T (&q[2]);
+  T (&q[3]);
+  T (&q[4]);        /* { dg-warning "subscript 4 is \(above|outside\) array bounds of .int\\\[3]." } */
+  T (&q[max]);      /* { dg-warning "subscript \[0-9\]+ is \(above|outside\) array bounds of .int\\\[3]." } */
+}
+
+
+void test_global_short_2dim_array (void)
+{
+  extern short giar3_5[3][5];
+
+  short *p = giar3_5[0];
+
+  /* The access below isn't diagnosed because the reference is transformed
+     into MEM_REF (short*, &giar3_5, 0), i.e., *giar3_5[0][0].  */
+  T (p[MIN]);       /* { dg-warning "subscript -\[0-9\]+ is outside array bounds of .short int\\\[3]" "bug" { xfail *-*-*} } */
+  T (p[-1]);        /* { dg-warning "subscript -1 is outside array bounds of .short int\\\[3]" } */
+  T (p[0]);
+  T (p[1]);
+  T (p[2]);
+  T (p[15]);        /* { dg-warning "subscript 15 is outside array bounds of .short int\\\[3]" } */
+  T (p[MAX]);       /* { dg-warning "subscript -?\[0-9\]+ is outside array bounds of .short int\\\[3]" } */
+
+  T (&p[MIN]);      /* { dg-warning "subscript -\[0-9\]+ is \(below|outside\) array bounds of .short int\\\[3]" "bug" { xfail *-*-* } } */
+  T (&p[-1]);       /* { dg-warning "subscript -1 is \(below|outside\) array bounds of .short int\\\[3]" } */
+  T (&p[0]);
+  T (&p[1]);
+  T (&p[2]);
+  T (&p[3]);
+  T (&p[16]);       /* { dg-warning "subscript 16 is \(above|outside\) array bounds of .short int\\\[3]" } */
+  T (&p[MAX]);      /* { dg-warning "subscript -?\[0-9\]+ is \(above|outside\) array bounds of .short int\\\[3]" } */
+}
+
+
+void test_local_char_array (void)
+{
+  char ar1[1] = { 1 };
+  char *p = ar1;
+
+  T (p[MIN]);      /* { dg-warning "subscript -\[0-9\]+ is outside array bounds of .char\\\[1]." } */
+  T (p[-1]);       /* { dg-warning "subscript -1 is outside array bounds of .char\\\[1]." } */
+  T (p[0]);
+  T (p[1]);         /* { dg-warning "subscript 1 is outside array bounds of .char\\\[1]." } */
+  T (p[MAX]);       /* { dg-warning "subscript \[0-9\]+ is outside array bounds of .char\\\[1]." } */
+
+  T (&p[MIN]);     /* { dg-warning "subscript -\[0-9\]+ is \(below|outside\) array bounds of .char\\\[1]." } */
+  T (&p[-1]);      /* { dg-warning "subscript -1 is \(below|outside\) array bounds of .char\\\[1]." } */
+  T (&p[0]);
+  T (&p[1]);
+  T (&p[2]);        /* { dg-warning "subscript 2 is \(above|outside\) array bounds of .char\\\[1]." } */
+  T (&p[MAX]);      /* { dg-warning "subscript \[0-9\]+ is \(above|outside\) array bounds of .char\\\[1]." } */
+
+  char ar3[3] = { 1, 2, 3 };
+  p = ar3;
+
+  T (p[MIN]);       /* { dg-warning "subscript -\[0-9\]+ is outside array bounds of .char\\\[3]." } */
+  T (p[-1]);        /* { dg-warning "subscript -1 is outside array bounds of .char\\\[3]." } */
+  T (p[0]);
+  T (p[1]);
+  T (p[2]);
+  T (p[3]);         /* { dg-warning "subscript 3 is outside array bounds of .char\\\[3]." } */
+  T (p[MAX]);       /* { dg-warning "subscript \[0-9\]+ is outside array bounds of .char\\\[3]." } */
+
+  T (&p[MIN]);      /* { dg-warning "subscript -\[0-9\]+ is \(below|outside\) array bounds of .char\\\[3]." } */
+  T (&p[-1]);       /* { dg-warning "subscript -1 is \(below|outside\) array bounds of .char\\\[3]." } */
+  T (&p[0]);
+  T (&p[1]);
+  T (&p[2]);
+  T (&p[3]);
+  T (&p[4]);        /* { dg-warning "subscript 4 is \(above|outside\) array bounds of .char\\\[3]." } */
+  T (&p[MAX]);      /* { dg-warning "subscript \[0-9\]+ is \(above|outside\) array bounds of .char\\\[3]." } */
+}
+
+struct S
+{
+  int a[2], b[3];
+} s [4];
+
+void test_struct_array_cst (void)
+{
+  T (s[0].a[0] + s[0].a[1] + s[0].b[0] + s[0].b[1] + s[0].b[2] + s[0].b[2]
+     + s[1].a[0] + s[1].a[1] + s[1].b[0] + s[1].b[1] + s[1].b[2] + s[1].b[2]
+     + s[2].a[0] + s[2].a[1] + s[2].b[0] + s[2].b[1] + s[2].b[2] + s[2].b[2]
+     + s[3].a[0] + s[3].a[1] + s[3].b[0] + s[3].b[1] + s[3].b[2] + s[3].b[2]);
+
+  T (&s[0].a[2],
+     &s[0].b[3],
+     &s[1].a[2],
+     &s[1].b[3],
+     &s[2].a[2],
+     &s[2].b[3],
+     &s[3].a[2],
+     &s[3].b[3]);
+
+  T (s[0].a[2]);    /* { dg-warning "subscript 2 is above array bounds of .int\\\[2\\\]." } */
+  T (s[0].b[3]);    /* { dg-warning "subscript 3 is above array bounds of .int\\\[3\\\]." } */
+  T (s[1].a[2]);    /* { dg-warning "subscript 2 is above array bounds of .int\\\[2\\\]." } */
+  T (s[1].b[3]);    /* { dg-warning "subscript 3 is above array bounds of .int\\\[3\\\]." } */
+  T (s[2].a[2]);    /* { dg-warning "subscript 2 is above array bounds of .int\\\[2\\\]." } */
+  T (s[2].b[3]);    /* { dg-warning "subscript 3 is above array bounds of .int\\\[3\\\]." } */
+  T (s[3].a[2]);    /* { dg-warning "subscript 2 is above array bounds of .int\\\[2\\\]." } */
+  T (s[3].b[3]);    /* { dg-warning "subscript 3 is above array bounds of .int\\\[3\\\]." } */
+
+  T (s[4].a[0]);    /* { dg-warning "subscript 4 is above array bounds of .struct S\\\[4\\\]." } */
+  T (s[4].a[2]);    /* { dg-warning "subscript 4 is above array bounds of .struct S\\\[4\\\]." } */
+                    /* { dg-warning "subscript 2 is above array bounds of .int\\\[2\\\]." "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-31.c b/gcc/testsuite/gcc.dg/Warray-bounds-31.c
new file mode 100644 (file)
index 0000000..e0be1e5
--- /dev/null
@@ -0,0 +1,248 @@
+/* PR tree-optimization/83776: missing -Warray-bounds indexing past the end
+   of a string literal
+   Test to exercise detection of out-of-bounds indices into narrow string
+   literals.
+   { dg-do compile }
+   { dg-options "-O2 -Warray-bounds -ftrack-macro-expansion=0" } */
+
+#include "range.h"
+
+#define MAX DIFF_MAX
+#define MIN DIFF_MIN
+
+#define S1 "1"
+#define S3 "123"
+#define S7 "1234567"
+#define S8 "12345678"
+#define S9 "123456789"
+
+void sink (int, ...);
+
+#define T(expr)   sink (0, expr)
+
+
+void narrow_direct_cst (void)
+{
+  T (S1[MIN]);                /* { dg-warning "array subscript -\[0-9\]+ is below array bounds of .char\\\[2]" "" { xfail *-*-* } } */
+  T (S1[-1]);                 /* { dg-warning "array subscript -1 is below array bounds of .char\\\[2]" } */
+  T (S1[0]);
+  T (S1[1]);
+  T (S1[2]);                  /* { dg-warning "array subscript 2 is above array bounds of .char\\\[2]" } */
+  T (S1[MAX]);                /* { dg-warning "array subscript \[0-9\]+ is above array bounds of .char\\\[2]" } */
+
+  T (&S1[MIN]);               /* { dg-warning "array subscript -\[0-9\]+ is below array bounds of .char\\\[2]" } */
+  T (&S1[-1]);                /* { dg-warning "array subscript -1 is below array bounds of .char\\\[2]" } */
+  T (&S1[0]);
+  T (&S1[2]);
+  T (&S1[3]);                 /* { dg-warning "array subscript 3 is above array bounds of .char\\\[2]" } */
+  T (&S1[MAX]);               /* { dg-warning "array subscript \[0-9\]+ is above array bounds of .char\\\[2]" } */
+
+  T (S9[MIN]);                /* { dg-warning "array subscript -\[0-9\]+ is below array bounds of .char\\\[10]" "" { xfail *-*-* } } */
+  T (S9[-1]);                 /* { dg-warning "array subscript -1 is below array bounds of .char\\\[10]" } */
+  T (S9[9]);
+  T (S9[10]);                 /* { dg-warning "array subscript 10 is above array bounds of .char\\\[10]" } */
+  T (S9[11]);                 /* { dg-warning "array subscript 11 is above array bounds of .char\\\[10]" } */
+  T (S9[MAX]);                /* { dg-warning "array subscript \[0-9\]+ is above array bounds of .char\\\[10]" } */
+
+  T (&S9[MIN]);               /* { dg-warning "array subscript -\[0-9\]+ is below array bounds of .char\\\[10]" } */
+  T (&S9[-1]);                /* { dg-warning "array subscript -1 is below array bounds of .char\\\[10]" } */
+  T (&S9[9]);
+  T (&S9[10]);
+  T (&S9[11]);                 /* { dg-warning "array subscript 11 is above array bounds of .char\\\[10]" } */
+  T (&S9[MAX]);               /* { dg-warning "array subscript \[0-9\]+ is above array bounds of .char\\\[10]" } */
+}
+
+void narrow_ptr_deref_cst (void)
+{
+  const char *p = S8 + 9;
+
+  T (*(p + MIN));             /* { dg-warning "array subscript -\[0-9\]+ is outside array bounds of .char\\\[9]." } */
+  T (*(p - 10));              /* { dg-warning "array subscript -1 is outside array bounds of .char\\\[9]." } */
+  T (*(p - 9));
+  T (*(p - 1));
+  T (*p);                     /* { dg-warning "array subscript 9 is outside array bounds of .char\\\[9]." } */
+  T (*(p + 1));               /* { dg-warning "array subscript 10 is outside array bounds of .char\\\[9]." } */
+  T (*(p + 2));               /* { dg-warning "array subscript 11 is outside array bounds of .char\\\[9]." } */
+}
+
+void narrow_ptr_index_cst (void)
+{
+  const char *p = S7;
+
+  T (p[MIN + 1]);             /* { dg-warning "array subscript -\[0-9\]+ is outside array bounds of .char\\\[8]." "bug 84047" { xfail *-*-* } } */
+  T (p[-1]);                  /* { dg-warning "array subscript -1 is outside array bounds of .char\\\[8]." } */
+  T (p[0]);
+  T (p[1]);
+  T (p[8]);                   /* { dg-warning "array subscript 8 is outside array bounds of .char\\\[8]." } */
+  T (p[99]);                  /* { dg-warning "array subscript 99 is outside array bounds of .char\\\[8]." } */
+  T (p[MAX]);                 /* { dg-warning "array subscript \[0-9\]+ is outside array bounds of .char\\\[8]." } */
+
+  T (&p[MIN + 1]);            /* { dg-warning "array subscript -\[0-9\]+ is \(below|outside\) array bounds of .char\\\[8]." } */
+  T (&p[-1]);                 /* { dg-warning "array subscript -1 is \(below|outside\) array bounds of .char\\\[8]." } */
+  T (&p[0]);
+  T (&p[1]);
+  T (&p[8]);
+  T (&p[9]);                  /* { dg-warning "array subscript 9 is \(above|outside\) array bounds of .char\\\[8]." } */
+  T (&p[99]);                 /* { dg-warning "array subscript 99 is \(above|outside\) array bounds of .char\\\[8]." } */
+  T (&p[MAX]);                /* { dg-warning "array subscript \[0-9\]+ is \(above|outside\) array bounds of .char\\\[8]." } */
+
+  const char *q = S8 + 4;
+  T (q[MIN + 1]);             /* { dg-warning "array subscript -?\[0-9\]+ is outside array bounds of .char\\\[9]." "bug 84047" { xfail *-*-* } } */
+  T (q[-5]);                  /* { dg-warning "array subscript -1 is outside array bounds of .char\\\[9]." } */
+  T (q[-4]);
+  T (q[0]);
+  T (q[1]);
+  T (q[3]);
+  T (q[4]);
+  T (q[5]);                   /* { dg-warning "array subscript 9 is outside array bounds of .char\\\[9]." } */
+  T (q[99]);                  /* { dg-warning "array subscript 103 is outside array bounds of .char\\\[9]." } */
+  T (q[MAX - 4]);             /* { dg-warning "array subscript \[0-9\]+ is outside array bounds of .char\\\[9]." } */
+  T (q[MAX - 3]);             /* { dg-warning "array subscript \[0-9\]+ is outside array bounds of .char\\\[9]." "bug 84047" { xfail *-*-* } } */
+
+  T (&q[MIN + 1]);            /* { dg-warning "array subscript -?\[0-9\]+ is \(below|outside\) array bounds of .char\\\[9]." } */
+  T (&q[-5]);                 /* { dg-warning "array subscript -1 is \(below|outside\) array bounds of .char\\\[9]." } */
+  T (&q[-4]);
+  T (&q[0]);
+  T (&q[1]);
+  T (&q[5]);
+  T (&q[6]);                  /* { dg-warning "array subscript 10 is \(above|outside\) array bounds of .char\\\[9]." } */
+  T (&q[99]);                 /* { dg-warning "array subscript 103 is \(above|outside\) array bounds of .char\\\[9]." } */
+  T (&q[MAX - 4]);            /* { dg-warning "array subscript \[0-9\]+ is \(above|outside\) array bounds of .char\\\[9]." } */
+  T (&q[MAX - 3]);            /* { dg-warning "array subscript -?\[0-9\]+ is \(below|outside\) array bounds of .char\\\[9]." } */
+}
+
+
+void narrow_direct_range (ptrdiff_t i, size_t j)
+{
+  T (S3[i]);
+  T (S9[j]);
+
+  T (S3[SR (MIN, -1)]);       /* { dg-warning "array subscript -1 is below array bounds of .char\\\[4]" } */
+  T (S3[SR (MIN, 0)]);
+  T (S3[SR (-2, -1)]);        /* { dg-warning "array subscript -1 is below array bounds of .char\\\[4]" } */
+  T (S3[SR (1, 2)]);
+  T (S3[SR (1, 999)]);
+  T (S3[SR (2, 999)]);
+  T (S3[SR (3, 999)]);
+  T (S3[SR (4, 999)]);       /* { dg-warning "array subscript 4 is above array bounds of .char\\\[4]" } */
+
+  T (&S3[SR (MIN, -1)]);      /* { dg-warning "array subscript -1 is below array bounds of .char\\\[4]" } */
+  T (&S3[SR (MIN, 0)]);
+  T (&S3[SR (-2, -1)]);       /* { dg-warning "array subscript -1 is below array bounds of .char\\\[4]" } */
+  T (&S3[SR (1, 2)]);
+  T (&S3[SR (1, 999)]);
+  T (&S3[SR (2, 999)]);
+  T (&S3[SR (4, 999)]);
+  T (&S3[SR (5, 999)]);      /* { dg-warning "array subscript 5 is above array bounds of .char\\\[4]" } */
+
+  T (S9[SR (MIN, -9)]);       /* { dg-warning "array subscript -9 is below array bounds of .char\\\[10]" } */
+  T (S9[SR (MIN, -1)]);       /* { dg-warning "array subscript -1 is below array bounds of .char\\\[10]" } */
+  T (S9[SR (MIN, 0)]);
+  T (S9[SR (-2, -1)]);        /* { dg-warning "array subscript -1 is below array bounds of .char\\\[10]" } */
+  T (S9[SR (1, 2)]);
+  T (S9[SR (1, 9)]);
+  T (S9[SR (1, 999)]);
+  T (S9[SR (9, 999)]);
+  T (S9[SR (10, 999)]);       /* { dg-warning "array subscript 10 is above array bounds of .char\\\[10]" } */
+  T (S9[SR (99, MAX)]);       /* { dg-warning "array subscript 99 is above array bounds of .char\\\[10]" } */
+}
+
+
+void narrow_ptr_deref_range (ptrdiff_t i, size_t j)
+{
+  const char *p;
+
+  p = S1 + i;
+  T (*p);
+
+  p = S1 + j;
+  T (*p);
+
+  p = S1 + SR (-999, 999);
+  T (*p);
+
+  p = S1 + SR (-1, 1);
+  T (*p);
+
+  p = S1 + SR (-1, 0);
+  T (*p);
+
+  p = S1 + SR (0, 1);
+  T (*p);
+
+  p = S1 + SR (1, 2);
+  T (*p);
+
+  p = S1 + SR (2, 3);
+  T (*p);                     /* { dg-warning "array subscript \\\[2, 3] is outside array bounds of .char\\\[2]." } */
+
+  p = S1 + SR (9, 99);
+  T (*p);                     /* { dg-warning "array subscript \\\[9, 99] is outside array bounds of .char\\\[2]." } */
+
+  p = S8 + SR (-999, 999);
+  T (*p);
+
+  p = S8 + SR (-9, -1);
+  T (*p);                     /* { dg-warning "array subscript \\\[-9, -1] is outside array bounds of .char\\\[9]." } */
+
+  p = S8 + SR (-9, 0);
+  T (*p);
+
+  p = S8 + SR (-9, 9);
+  T (*p);
+
+  p = S8 + SR (-9, 123);
+  T (*p);
+
+  p = S8 + SR (8, 123);
+  T (*p);
+
+  p = S8 + SR (9, 123);
+  T (*p);                     /* { dg-warning "array subscript \\\[9, 123] is outside array bounds of .char\\\[9]." } */
+
+  {
+    const char *p1 = S3 + i;
+    const char *p2 = p1 + i;
+    const char *p3 = p2 + i;
+    const char *p4 = p3 + i;
+    const char *p5 = p4 + i;
+
+    T (*p1);
+    T (*p2);
+    T (*p3);
+    T (*p4);
+    T (*p5);
+  }
+
+  {
+    i = SR (1, 2);
+
+    const char *p1 = S3 +  SR (1, DIFF_MAX - 1);
+    const char *p2 = p1 + i;
+    const char *p3 = p2 + i;
+    const char *p4 = p3 + i;
+    const char *p5 = p4 + i;
+
+    T (*p1);
+    T (*p2);
+    T (*p3);
+    T (*p4);                  /* { dg-warning "array subscript \\\[4, \[0-9\]+] is outside array bounds of .char\\\[4]." } */
+    T (*p5);                  /* { dg-warning "array subscript \\\[5, \[0-9\]+] is outside array bounds of .char\\\[4]." } */
+  }
+}
+
+
+void narrow_ptr_index_range (void)
+{
+  const char *p;
+
+  p = S7;
+  T (p[SR (-9, -1)]);         /* { dg-warning "array subscript \\\[-9, -1] is outside array bounds of .char\\\[8]." } */
+  T (p[SR (-8, 0)]);
+  T (p[SR (0, MAX)]);
+  T (p[SR (1, 9)]);
+  T (p[SR (8, 9)]);           /* { dg-warning "array subscript \\\[8, 9] is outside array bounds of .char\\\[8]." } */
+
+  p = S7 + SR (4, 6);
+  T (p[5]);                   /* { dg-warning "array subscript \\\[9, 11] is outside array bounds of .char\\\[8]." } */
+}
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-32.c b/gcc/testsuite/gcc.dg/Warray-bounds-32.c
new file mode 100644 (file)
index 0000000..9512764
--- /dev/null
@@ -0,0 +1,185 @@
+/* PR tree-optimization/83776: missing -Warray-bounds indexing past the end
+   of a string literal
+   Test to exercise indices into wide string literals.
+   { dg-do compile }
+   { dg-options "-O2 -Warray-bounds -ftrack-macro-expansion=0" } */
+
+#include "range.h"
+
+#define MAX DIFF_MAX
+#define MIN DIFF_MIN
+
+typedef __WCHAR_TYPE__ wchar_t;
+
+#define W2 L"12"
+#define W3 L"123"
+#define W4 L"1234"
+#define W7 L"1234567"
+#define W8 L"12345678"
+#define W9 L"123456789"
+
+void sink (int);
+
+#define T(expr)   sink (expr)
+
+
+void wide_direct_cst (void)
+{
+  T (W9[MIN]);                /* { dg-warning "array subscript -\[0-9\]+ is below array bounds of .\[a-z \]+\\\[10]" "" } */
+  T (W9[-1]);                 /* { dg-warning "array subscript -1 is below array bounds of .\[a-z \]+\\\[10]" } */
+  T (W9[11]);                 /* { dg-warning "array subscript 11 is above array bounds of .\[a-z \]+\\\[10]" } */
+  T (W9[MAX]);                /* { dg-warning "array subscript \[0-9\]+ is above array bounds of .\[a-z \]+\\\[10]" } */
+
+}
+
+void wide_ptr_deref_cst (void)
+{
+  const wchar_t *p = W8 + 9;
+  T (*p);                     /* { dg-warning "array subscript 9 is outside array bounds of .\[a-z \]+\\\[9]." } */
+  T (p[1]);                   /* { dg-warning "array subscript 10 is outside array bounds of .\[a-z \]+\\\[9]." } */
+  T (p[99]);                  /* { dg-warning "array subscript 108 is outside array bounds of .\[a-z \]+\\\[9]." } */
+}
+
+void wide_ptr_index_cst (void)
+{
+  const wchar_t *p = W7;
+
+  T (p[1]);
+  T (p[8]);                   /* { dg-warning "array subscript 8 is outside array bounds of .\[a-z \]+\\\[8]." } */
+  T (p[99]);                  /* { dg-warning "array subscript 99 is outside array bounds of .\[a-z \]+\\\[8]." } */
+  T (p[MAX]);                 /* { dg-warning "array subscript -?\[0-9\]+ is outside array bounds of .\[a-z \]+\\\[8]." } */
+}
+
+
+void wide_direct_range (ptrdiff_t i, size_t j)
+{
+  T (W9[i]);
+  T (W9[j]);
+
+  T (W9[SR (MIN, -9)]);       /* { dg-warning "array subscript -9 is below array bounds of .\[a-z \]+\\\[10]" } */
+  T (W9[SR (MIN, -1)]);       /* { dg-warning "array subscript -1 is below array bounds of .\[a-z \]+\\\[10]" } */
+  T (W9[SR (MIN, 0)]);
+  T (W9[SR (-2, -1)]);        /* { dg-warning "array subscript -1 is below array bounds of .\[a-z \]+\\\[10]" } */
+  T (W9[SR (1, 2)]);
+  T (W9[SR (1, 9)]);
+  T (W9[SR (1, 999)]);
+  T (W9[SR (9, 999)]);
+  T (W9[SR (10, 999)]);       /* { dg-warning "array subscript 10 is above array bounds of .\[a-z \]+\\\[10]" } */
+  T (W9[SR (99, MAX)]);       /* { dg-warning "array subscript 99 is above array bounds of .\[a-z \]+\\\[10]" } */
+}
+
+void wide_ptr_deref_range (ptrdiff_t i, size_t j)
+{
+  const wchar_t *p;
+
+  p = W8 + i;
+  T (*p);
+
+  p = W8 + j;
+  T (*p);
+
+  p = W8 + SR (-9, -1);
+  T (*p);                     /* { dg-warning "array subscript \\\[-9, -1] is outside array bounds of .\[a-z \]+\\\[9]." } */
+
+  p = W8 + SR (-9, 0);
+  T (*p);
+
+  p = W8 + SR (-9, 9);
+  T (*p);
+
+  p = W8 + SR (9, 123);
+  T (*p);                     /* { dg-warning "array subscript \\\[9, 123] is outside array bounds of .\[a-z \]+\\\[9]." } */
+}
+
+void wide_ptr_index_range (void)
+{
+  const wchar_t *p;
+
+  p = W7;
+  T (p[SR (-9, -1)]);         /* { dg-warning "array subscript \\\[-9, -1] is outside array bounds of .\[a-z \]+\\\[8]." } */
+  T (p[SR (-8, 0)]);
+  T (p[SR (0, MAX)]);
+  T (p[SR (1, 9)]);
+  T (p[SR (8, 9)]);           /* { dg-warning "array subscript \\\[8, 9] is outside array bounds of .\[a-z \]+\\\[8]." } */
+
+  p = W7 + SR (4, 6);
+  T (p[5]);                   /* { dg-warning "array subscript \\\[9, 11] is outside array bounds of .\[a-z \]+\\\[8]." } */
+}
+
+void wide_ptr_index_range_1 (void)
+{
+  {
+    int i = SR (1, 2);
+    const wchar_t *p1 = W2 + i;
+
+    T (p1[0]);
+  }
+  {
+    int i = SR (1, 2);
+    const wchar_t *p1 = W2 + i;
+
+    T (p1[1]);
+  }
+  {
+    int i = SR (1, 2);
+    const wchar_t *p1 = W2 + i;
+
+    T (p1[2]);                /* { dg-warning "array subscript \\\[3, 4] is outside array bounds of .\[a-z \]+\\\[3]." } */
+  }
+}
+
+void wide_ptr_index_range_chain (void)
+{
+  int i = SR (1, 2);
+  {
+    const wchar_t *p1 = W2 + i;
+    const wchar_t *p2 = p1 + i;
+    const wchar_t *p3 = p2 + i;
+
+    T (p1[-3]);               /* { dg-warning "array subscript \\\[-2, -1] is outside array bounds of .\[a-z \]+\\\[3]." } */
+    T (p1[-2]);
+    T (p1[-1]);
+    T (p1[0]);
+    T (p1[1]);
+    T (p1[2]);                /* { dg-warning "array subscript \\\[3, 4] is outside array bounds of .\[a-z \]+\\\[3]." } */
+
+    T (p2[-5]);               /* { dg-warning "array subscript \\\[-3, -1] is outside array bounds of .\[a-z \]+\\\[3]." } */
+    T (p2[-4]);
+    T (p2[-1]);
+    T (p2[0]);
+    T (p2[1]);                /* { dg-warning "array subscript \\\[3, 5] is outside array bounds of .\[a-z \]+\\\[3]." } */
+
+    T (p3[0]);                /* { dg-warning "array subscript \\\[3, 6] is outside array bounds of .\[a-z \]+\\\[3]." } */
+    T (p3[1]);                /* { dg-warning "array subscript \\\[4, 7] is outside array bounds of .\[a-z \]+\\\[3]." } */
+    T (p3[9999]);             /* { dg-warning "array subscript \\\[10002, 10005] is outside array bounds of .\[a-z \]+\\\[3]." } */
+
+    /* Large offsets are indistinguishable from negative values.  */
+    T (p3[DIFF_MAX]);         /* { dg-warning "array subscript" "bug" { xfail *-*-* } } */
+  }
+
+  {
+    const wchar_t *p1 = W3 + i;
+    const wchar_t *p2 = p1 + i;
+    const wchar_t *p3 = p2 + i;
+    const wchar_t *p4 = p3 + i;
+
+    T (p1[-3]);               /* { dg-warning "array subscript \\\[-2, -1] is outside array bounds of .\[a-z \]+\\\[4]." } */
+    T (p1[-2]);
+    T (p1[1]);
+    T (p1[2]);
+    T (p1[3]);                /* { dg-warning "array subscript \\\[4, 5] is outside array bounds of .\[a-z \]+\\\[4]." } */
+
+    T (p3[1]);                /* { dg-warning "array subscript \\\[4, 7] is outside array bounds of .\[a-z \]+\\\[4]." } */
+  }
+}
+
+void wide_ptr_index_range_4 (void)
+{
+  int i = SR (1, 2);
+  const wchar_t *p1 = W4 + i;
+  const wchar_t *p2 = p1 + i;
+  const wchar_t *p3 = p2 + i;
+  const wchar_t *p4 = p3 + i;
+
+  T (p4[1]);                  /* { dg-warning "array subscript \\\[5, 9] is outside array bounds of .\[a-z \]+\\\[5]." } */
+}
index 170cccb..7ab8898 100644 (file)
@@ -4753,6 +4753,7 @@ class vrp_prop : public ssa_propagation_engine
   void vrp_finalize (bool);
   void check_all_array_refs (void);
   void check_array_ref (location_t, tree, bool);
+  void check_mem_ref (location_t, tree, bool);
   void search_for_addr_array (tree, location_t);
 
   class vr_values vr_values;
@@ -4905,21 +4906,282 @@ vrp_prop::check_array_ref (location_t location, tree ref,
     }
 }
 
+/* Checks one MEM_REF in REF, located at LOCATION, for out-of-bounds
+   references to string constants.  If VRP can determine that the array
+   subscript is a constant, check if it is outside valid range.
+   If the array subscript is a RANGE, warn if it is non-overlapping
+   with valid range.
+   IGNORE_OFF_BY_ONE is true if the MEM_REF is inside an ADDR_EXPR
+   (used to allow one-past-the-end indices for code that takes
+   the address of the just-past-the-end element of an array).  */
+
+void
+vrp_prop::check_mem_ref (location_t location, tree ref, bool ignore_off_by_one)
+{
+  if (TREE_NO_WARNING (ref))
+    return;
+
+  tree arg = TREE_OPERAND (ref, 0);
+  /* The constant and variable offset of the reference.  */
+  tree cstoff = TREE_OPERAND (ref, 1);
+  tree varoff = NULL_TREE;
+
+  const offset_int maxobjsize = tree_to_shwi (max_object_size ());
+
+  /* The array or string constant bounds in bytes.  Initially set
+     to [-MAXOBJSIZE - 1, MAXOBJSIZE]  until a tighter bound is
+     determined.  */
+  offset_int arrbounds[2] = { -maxobjsize - 1, maxobjsize };
+
+  /* The minimum and maximum intermediate offset.  For a reference
+     to be valid, not only does the final offset/subscript must be
+     in bounds but all intermediate offsets should be as well.
+     GCC may be able to deal gracefully with such out-of-bounds
+     offsets so the checking is only enbaled at -Warray-bounds=2
+     where it may help detect bugs in uses of the intermediate
+     offsets that could otherwise not be detectable.  */
+  offset_int ioff = wi::to_offset (fold_convert (ptrdiff_type_node, cstoff));
+  offset_int extrema[2] = { 0, wi::abs (ioff) };
+
+  /* The range of the byte offset into the reference.  */
+  offset_int offrange[2] = { 0, 0 };
+
+  value_range *vr = NULL;
+
+  /* Determine the offsets and increment OFFRANGE for the bounds of each.
+     The loop computes the the range of the final offset for expressions
+     such as (A + i0 + ... + iN)[CSTOFF] where i0 through iN are SSA_NAMEs
+     in some range.  */
+  while (TREE_CODE (arg) == SSA_NAME)
+    {
+      gimple *def = SSA_NAME_DEF_STMT (arg);
+      if (!is_gimple_assign (def))
+       break;
+
+      tree_code code = gimple_assign_rhs_code (def);
+      if (code == POINTER_PLUS_EXPR)
+       {
+         arg = gimple_assign_rhs1 (def);
+         varoff = gimple_assign_rhs2 (def);
+       }
+      else if (code == ASSERT_EXPR)
+       {
+         arg = TREE_OPERAND (gimple_assign_rhs1 (def), 0);
+         continue;
+       }
+      else
+       return;
+
+      /* VAROFF should always be a SSA_NAME here (and not even
+        INTEGER_CST) but there's no point in taking chances.  */
+      if (TREE_CODE (varoff) != SSA_NAME)
+       break;
+
+      vr = get_value_range (varoff);
+      if (!vr || vr->type == VR_UNDEFINED || !vr->min || !vr->max)
+       break;
+
+      if (TREE_CODE (vr->min) != INTEGER_CST
+          || TREE_CODE (vr->max) != INTEGER_CST)
+        break;
+
+      if (vr->type == VR_RANGE)
+       {
+         if (tree_int_cst_lt (vr->min, vr->max))
+           {
+             offset_int min
+               = wi::to_offset (fold_convert (ptrdiff_type_node, vr->min));
+             offset_int max
+               = wi::to_offset (fold_convert (ptrdiff_type_node, vr->max));
+             if (min < max)
+               {
+                 offrange[0] += min;
+                 offrange[1] += max;
+               }
+             else
+               {
+                 offrange[0] += max;
+                 offrange[1] += min;
+               }
+           }
+         else
+           {
+             /* Conservatively add [-MAXOBJSIZE -1, MAXOBJSIZE]
+                to OFFRANGE.  */
+             offrange[0] += arrbounds[0];
+             offrange[1] += arrbounds[1];
+           }
+       }
+      else
+       {
+         /* For an anti-range, analogously to the above, conservatively
+            add [-MAXOBJSIZE -1, MAXOBJSIZE] to OFFRANGE.  */
+         offrange[0] += arrbounds[0];
+         offrange[1] += arrbounds[1];
+       }
+
+      /* Keep track of the minimum and maximum offset.  */
+      if (offrange[1] < 0 && offrange[1] < extrema[0])
+       extrema[0] = offrange[1];
+      if (offrange[0] > 0 && offrange[0] > extrema[1])
+       extrema[1] = offrange[0];
+
+      if (offrange[0] < arrbounds[0])
+       offrange[0] = arrbounds[0];
+
+      if (offrange[1] > arrbounds[1])
+       offrange[1] = arrbounds[1];
+    }
+
+  if (TREE_CODE (arg) == ADDR_EXPR)
+    {
+      arg = TREE_OPERAND (arg, 0);
+      if (TREE_CODE (arg) != STRING_CST
+         && TREE_CODE (arg) != VAR_DECL)
+       return;
+    }
+  else
+    return;
+
+  /* The type of the object being referred to.  It can be an array,
+     string literal, or a non-array type when the MEM_REF represents
+     a reference/subscript via a pointer to an object that is not
+     an element of an array.  References to members of structs and
+     unions are excluded because MEM_REF doesn't make it possible
+     to identify the member where the reference originated.  */
+  tree reftype = TREE_TYPE (arg);
+  if (POINTER_TYPE_P (reftype)
+      || RECORD_OR_UNION_TYPE_P (reftype))
+    return;
+
+  offset_int eltsize;
+  if (TREE_CODE (reftype) == ARRAY_TYPE)
+    {
+      eltsize = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (reftype)));
+
+      if (tree dom = TYPE_DOMAIN (reftype))
+       {
+         tree bnds[] = { TYPE_MIN_VALUE (dom), TYPE_MAX_VALUE (dom) };
+         if (array_at_struct_end_p (arg)
+             || !bnds[0] || !bnds[1])
+           {
+             arrbounds[0] = 0;
+             arrbounds[1] = wi::lrshift (maxobjsize, wi::floor_log2 (eltsize));
+           }
+         else
+           {
+             arrbounds[0] = wi::to_offset (bnds[0]) * eltsize;
+             arrbounds[1] = (wi::to_offset (bnds[1]) + 1) * eltsize;
+           }
+       }
+      else
+       {
+         arrbounds[0] = 0;
+         arrbounds[1] = wi::lrshift (maxobjsize, wi::floor_log2 (eltsize));
+       }
+
+      if (TREE_CODE (ref) == MEM_REF)
+       {
+         /* For MEM_REF determine a tighter bound of the non-array
+            element type.  */
+         tree eltype = TREE_TYPE (reftype);
+         while (TREE_CODE (eltype) == ARRAY_TYPE)
+           eltype = TREE_TYPE (eltype);
+         eltsize = wi::to_offset (TYPE_SIZE_UNIT (eltype));
+       }
+    }
+  else
+    {
+      eltsize = 1;
+      arrbounds[0] = 0;
+      arrbounds[1] = wi::to_offset (TYPE_SIZE_UNIT (reftype));
+    }
+
+  offrange[0] += ioff;
+  offrange[1] += ioff;
+
+  /* Compute the more permissive upper bound when IGNORE_OFF_BY_ONE
+     is set (when taking the address of the one-past-last element
+     of an array) but always use the stricter bound in diagnostics. */
+  offset_int ubound = arrbounds[1];
+  if (ignore_off_by_one)
+    ubound += 1;
+
+  if (offrange[0] >= ubound || offrange[1] < arrbounds[0])
+    {
+      /* Treat a reference to a non-array object as one to an array
+        of a single element.  */
+      if (TREE_CODE (reftype) != ARRAY_TYPE)
+       reftype = build_array_type_nelts (reftype, 1);
+
+      if (TREE_CODE (ref) == MEM_REF)
+       {
+         /* Extract the element type out of MEM_REF and use its size
+            to compute the index to print in the diagnostic; arrays
+            in MEM_REF don't mean anything.   */
+         tree type = TREE_TYPE (ref);
+         while (TREE_CODE (type) == ARRAY_TYPE)
+           type = TREE_TYPE (type);
+         tree size = TYPE_SIZE_UNIT (type);
+         offrange[0] = offrange[0] / wi::to_offset (size);
+         offrange[1] = offrange[1] / wi::to_offset (size);
+       }
+      else
+       {
+         /* For anything other than MEM_REF, compute the index to
+            print in the diagnostic as the offset over element size.  */
+         offrange[0] = offrange[0] / eltsize;
+         offrange[1] = offrange[1] / eltsize;
+       }
+
+      if (offrange[0] == offrange[1])
+       warning_at (location, OPT_Warray_bounds,
+                   "array subscript %wi is outside array bounds "
+                   "of %qT",
+                   offrange[0].to_shwi (), reftype);
+      else
+       warning_at (location, OPT_Warray_bounds,
+                   "array subscript [%wi, %wi] is outside array bounds "
+                   "of %qT",
+                   offrange[0].to_shwi (), offrange[1].to_shwi (), reftype);
+      TREE_NO_WARNING (ref) = 1;
+      return;
+    }
+
+  if (warn_array_bounds < 2)
+    return;
+
+  /* At level 2 check also intermediate offsets.  */
+  int i = 0;
+  if (extrema[i] < -arrbounds[1] || extrema[i = 1] > ubound)
+    {
+      HOST_WIDE_INT tmpidx = extrema[i].to_shwi () / eltsize.to_shwi ();
+
+      warning_at (location, OPT_Warray_bounds,
+                 "intermediate array offset %wi is outside array bounds "
+                 "of %qT",
+                 tmpidx,  reftype);
+      TREE_NO_WARNING (ref) = 1;
+    }
+}
+
 /* Searches if the expr T, located at LOCATION computes
    address of an ARRAY_REF, and call check_array_ref on it.  */
 
 void
 vrp_prop::search_for_addr_array (tree t, location_t location)
 {
-  /* Check each ARRAY_REFs in the reference chain. */
+  /* Check each ARRAY_REF and MEM_REF in the reference chain. */
   do
     {
       if (TREE_CODE (t) == ARRAY_REF)
        check_array_ref (location, t, true /*ignore_off_by_one*/);
+      else if (TREE_CODE (t) == MEM_REF)
+       check_mem_ref (location, t, true /*ignore_off_by_one*/);
 
       t = TREE_OPERAND (t, 0);
     }
-  while (handled_component_p (t));
+  while (handled_component_p (t) || TREE_CODE (t) == MEM_REF);
 
   if (TREE_CODE (t) == MEM_REF
       && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
@@ -5001,7 +5263,8 @@ check_array_bounds (tree *tp, int *walk_subtree, void *data)
   vrp_prop *vrp_prop = (class vrp_prop *)wi->info;
   if (TREE_CODE (t) == ARRAY_REF)
     vrp_prop->check_array_ref (location, t, false /*ignore_off_by_one*/);
-
+  else if (TREE_CODE (t) == MEM_REF)
+    vrp_prop->check_mem_ref (location, t, false /*ignore_off_by_one*/);
   else if (TREE_CODE (t) == ADDR_EXPR)
     {
       vrp_prop->search_for_addr_array (t, location);