From d893b683f40884cd00b5beb392566ecc7b67f721 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Thu, 19 Jul 2018 23:36:34 +0000 Subject: [PATCH] PR tree-optimization/84047 - missing -Warray-bounds on an out-of-bounds index into an array 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 | 7 + gcc/testsuite/ChangeLog | 9 ++ gcc/testsuite/gcc.dg/Warray-bounds-29.c | 150 ++++++++++++++++++ gcc/testsuite/gcc.dg/Warray-bounds-30.c | 200 ++++++++++++++++++++++++ gcc/testsuite/gcc.dg/Warray-bounds-31.c | 248 +++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/Warray-bounds-32.c | 185 ++++++++++++++++++++++ gcc/tree-vrp.c | 269 +++++++++++++++++++++++++++++++- 7 files changed, 1065 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/Warray-bounds-29.c create mode 100644 gcc/testsuite/gcc.dg/Warray-bounds-30.c create mode 100644 gcc/testsuite/gcc.dg/Warray-bounds-31.c create mode 100644 gcc/testsuite/gcc.dg/Warray-bounds-32.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 264d051..09329f4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,12 @@ 2018-07-19 Martin Sebor + 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 + * align.h (align_flags): Use member initialization. 2018-07-19 David Malcolm diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b8b309f..8eccef1 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2018-07-19 Martin Sebor + + 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 Richard Henderson diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-29.c b/gcc/testsuite/gcc.dg/Warray-bounds-29.c new file mode 100644 index 0000000..72c5d1c --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-29.c @@ -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 index 0000000..ac7e9a6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-30.c @@ -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 index 0000000..e0be1e5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-31.c @@ -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 index 0000000..9512764 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-32.c @@ -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]." } */ +} diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 170cccb..7ab8898 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -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); -- 2.7.4