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


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

[PATCH] restore -Warray-bounds for string literals (PR 83776)


PR tree-optimization/83776 - [6/7/8 Regression] missing
-Warray-bounds indexing past the end of a string literal,
identified a not-so-recent improvement to constant propagation
as the reason for GCC no longer being able to detect out-of-
bounds accesses to string literals.  The root cause is that
the change caused accesses to strings to be transformed into
MEM_REFs that the -Warray-bounds checker isn't prepared to
handle.  A simple example is:

  int h (void)
  {
    const char *p = "1234";
    return p[16];   // missing -Warray-bounds
  }

To fix the regression the attached patch extends the array bounds
checker to handle the small subset of MEM_REF expressions that
refer to string literals but stops of short of doing more than
that.  There are outstanding gaps in the detection that the patch
intentionally doesn't handle.  They are either caused by other
regressions (PR 84047) or by other latent bugs/limitations, or
by limitations in the approach I took to try to keep the patch
simple.  I hope to address some of those in a follow-up patch
for GCC 9.

Martin
PR tree-optimization/83776 - [6/7/8 Regression] missing -Warray-bounds indexing past the end of a string literal

gcc/ChangeLog:

	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
	* gcc.dg/Warray-bounds-27.c: New test.
	* gcc.dg/Warray-bounds-28.c: New test.
	* gcc.dg/Warray-bounds-29.c: New test.

diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-27.c b/gcc/testsuite/gcc.dg/Warray-bounds-27.c
new file mode 100644
index 0000000..ccc88cd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-27.c
@@ -0,0 +1,223 @@
+/* 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 array bounds of .char\\\[8]." } */
+  T (&p[-1]);                 /* { dg-warning "array subscript -1 is below array bounds of .char\\\[8]." } */
+  T (&p[0]);
+  T (&p[1]);
+  T (&p[8]);
+  T (&p[9]);                  /* { dg-warning "array subscript 9 is above array bounds of .char\\\[8]." } */
+  T (&p[99]);                 /* { dg-warning "array subscript 99 is above array bounds of .char\\\[8]." } */
+  T (&p[MAX]);                /* { dg-warning "array subscript \[0-9\]+ is above 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 array bounds of .char\\\[9]." } */
+  T (&q[-5]);                 /* { dg-warning "array subscript -1 is below 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 array bounds of .char\\\[9]." } */
+  T (&q[99]);                 /* { dg-warning "array subscript 103 is above array bounds of .char\\\[9]." } */
+  T (&q[MAX - 4]);            /* { dg-warning "array subscript \[0-9\]+ is above array bounds of .char\\\[9]." } */
+  T (&q[MAX - 3]);            /* { dg-warning "array subscript -?\[0-9\]+ is below array bounds of .char\\\[9]." } */
+}
+
+
+void narrow_direct_var (int i)
+{
+  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_var (void)
+{
+  const char *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]." } */
+
+  ptrdiff_t 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_var (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-28.c b/gcc/testsuite/gcc.dg/Warray-bounds-28.c
new file mode 100644
index 0000000..7849767
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-28.c
@@ -0,0 +1,176 @@
+/* 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_var (ptrdiff_t i)
+{
+  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_var (ptrdiff_t i)
+{
+  const wchar_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_var (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_var_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_var_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_var_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/testsuite/gcc.dg/Warray-bounds-29.c b/gcc/testsuite/gcc.dg/Warray-bounds-29.c
new file mode 100644
index 0000000..7f89604
--- /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\) 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 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/tree-vrp.c b/gcc/tree-vrp.c
index 3294bde..b2e45c9 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -4763,6 +4763,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);
   void search_for_addr_array (tree, location_t);
 
   class vr_values vr_values;
@@ -4781,6 +4782,7 @@ class vrp_prop : public ssa_propagation_engine
   void extract_range_from_phi_node (gphi *phi, value_range *vr)
     { vr_values.extract_range_from_phi_node (phi, vr); }
 };
+
 /* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible arrays
    and "struct" hacks. If VRP can determine that the
    array subscript is a constant, check if it is outside valid
@@ -4915,6 +4917,179 @@ 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.  */
+
+void
+vrp_prop::check_mem_ref (location_t location, tree ref)
+{
+  if (TREE_NO_WARNING (ref))
+    return;
+
+  tree arg = TREE_OPERAND (ref, 0);
+  tree cstoff = TREE_OPERAND (ref, 1);
+  tree varoff = NULL_TREE;
+
+  const offset_int maxobjsize = tree_to_shwi (max_object_size ());
+
+  /* The string constant bounds in bytes.  Initially set to [0, MAXOBJSIZE]
+     until a tighter bound is determined.  */
+  offset_int strbounds[2];
+  strbounds[1] = maxobjsize;
+  strbounds[0] = -strbounds[1] - 1;
+
+  /* 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 must be as well. */
+  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.  */
+  while (TREE_CODE (arg) == SSA_NAME)
+    {
+      gimple *def = SSA_NAME_DEF_STMT (arg);
+      if (!is_gimple_assign (def))
+	{
+	  if (tree var = SSA_NAME_VAR (arg))
+	    arg = var;
+	  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;
+
+      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;
+
+      offset_int ofr[] = {
+	wi::to_offset (fold_convert (ptrdiff_type_node, vr->min)),
+	wi::to_offset (fold_convert (ptrdiff_type_node, vr->max))
+      };
+
+      if (vr->type == VR_RANGE)
+	{
+	  if (ofr[0] < ofr[1])
+	    {
+	      offrange[0] += ofr[0];
+	      offrange[1] += ofr[1];
+	    }
+	  else
+	    {
+	      offrange[0] += strbounds[0];
+	      offrange[1] += strbounds[1];
+	    }
+	}
+      else
+	{
+	  offrange[0] += strbounds[0];
+	  offrange[1] += strbounds[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] < strbounds[0])
+	offrange[0] = strbounds[0];
+
+      if (offrange[1] > strbounds[1])
+	offrange[1] = strbounds[1];
+    }
+
+  /* Handle just string constants for now.  */
+  if (TREE_CODE (arg) == ADDR_EXPR)
+    {
+      arg = TREE_OPERAND (arg, 0);
+      if (TREE_CODE (arg) != STRING_CST)
+	return;
+    }
+  else
+    return;
+
+  tree strtype = TREE_TYPE (arg);
+
+  if (TREE_CODE (strtype) != ARRAY_TYPE)
+    return;
+
+  offrange[0] += ioff;
+  offrange[1] += ioff;
+
+  offset_int eltsize = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (strtype)));
+
+  tree dom = TYPE_DOMAIN (strtype);
+  strbounds[0] = wi::to_offset (TYPE_MIN_VALUE (dom)) * eltsize;
+  strbounds[1] = wi::to_offset (TYPE_MAX_VALUE (dom)) * eltsize;
+
+  if (offrange[0] > strbounds[1]
+      || offrange[1] < strbounds[0])
+    {
+      HOST_WIDE_INT idxrange[] = {
+	offrange[0].to_shwi () / eltsize.to_shwi (),
+	offrange[1].to_shwi () / eltsize.to_shwi ()
+      };
+
+      if (idxrange[0] == idxrange[1])
+	warning_at (location, OPT_Warray_bounds,
+		    "array subscript %wi is outside array bounds "
+		    "of %qT",
+		    idxrange[0], strtype);
+      else
+	warning_at (location, OPT_Warray_bounds,
+		    "array subscript [%wi, %wi] is outside array bounds "
+		    "of %qT",
+		    idxrange[0], idxrange[1], strtype);
+      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] < -strbounds[1]
+      || extrema[i = 1] > strbounds[1] + eltsize)
+    {
+      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,  strtype);
+      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.  */
 
@@ -5011,7 +5186,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);
   else if (TREE_CODE (t) == ADDR_EXPR)
     {
       vrp_prop->search_for_addr_array (t, location);

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