Commit d893b683 by Martin Sebor Committed by Martin Sebor

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
parent a34ab135
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>
......
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>
......
/* 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]." } */
}
/* 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 } */
}
/* 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]." } */
}
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment