Use the determined lower bound of the range of offsets in a PLUS_EXPR.
authorMartin Sebor <msebor@redhat.com>
Tue, 1 Sep 2020 22:02:19 +0000 (16:02 -0600)
committerMartin Sebor <msebor@redhat.com>
Tue, 1 Sep 2020 22:03:25 +0000 (16:03 -0600)
gcc/ChangeLog:

* builtins.c (compute_objsize):  Only replace the upper bound
of a POINTER_PLUS offset when it's less than the lower bound.

gcc/testsuite/ChangeLog:

* gcc.dg/Wstringop-overflow.c: Remove xfails.
* gcc.dg/Wstringop-overflow-42.c: New test.
* gcc.dg/Wstringop-overread-4.c: New test.

gcc/builtins.c
gcc/testsuite/gcc.dg/Wstringop-overflow-42.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wstringop-overflow.c
gcc/testsuite/gcc.dg/Wstringop-overread-4.c [new file with mode: 0644]

index bc35b071f0261c4d357f03357f9519d86ff58c2c..97f1a184dc61b01e4e3d6c004be059662d04754b 100644 (file)
@@ -4367,12 +4367,17 @@ compute_objsize (tree ptr, int ostype, access_ref *pref,
             offset to the maximum.  */
          offset_int orng[2];
          tree off = gimple_assign_rhs2 (stmt);
-         if (!get_range (off, SIGNED, orng, rvals)
-             || !wi::les_p (orng[0], orng[1]))
+         if (!get_range (off, SIGNED, orng, rvals))
            {
              orng[0] = wi::to_offset (TYPE_MIN_VALUE (ptrdiff_type_node));
              orng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node));
            }
+         else if (wi::lts_p (orng[1], orng[0]))
+           /* The upper bound is less than the lower bound when the integer
+              operand is the result of signed integer conversion to sizetype,
+              as in P + OFF + CST where OFF > 0.
+              Correct just the upper bound.  */
+           orng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node));
 
          pref->offrng[0] += orng[0];
          pref->offrng[1] += orng[1];
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-42.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-42.c
new file mode 100644 (file)
index 0000000..21a675a
--- /dev/null
@@ -0,0 +1,58 @@
+/* Verify -Wstringop-overflow a with destination pointer pointing either
+   before the beginning or past the end of an object.
+  { dg-do compile }
+  { dg-options "-O -Wall -Wno-array-bounds -Wno-restrict" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+char* strcpy (char *, const char *);
+
+
+extern char a[1];
+
+volatile char *d;
+
+void cpy_si_1_max (int i, const char *s)
+{
+  if (i < 1) i = 1;
+  d = strcpy (a + i, s);      // { dg-warning "writing 1 or more bytes into a region of size 0" }
+  d = strcpy (a + i + 1, s);  // { dg-warning "writing 1 or more bytes into a region of size 0" }
+}
+
+void cpy_ui_1_max (unsigned i, const char *s)
+{
+  if (i < 1) i = 1;
+  d = strcpy (a + i, s);      // { dg-warning "writing 1 or more bytes into a region of size 0" }
+  d = strcpy (a + i + 1, s);  // { dg-warning "writing 1 or more bytes into a region of size 0" "" { xfail ilp32 } }
+}
+
+void cpy_sl_1_max (long i, const char *s)
+{
+  if (i < 1) i = 1;
+  d = strcpy (a + i, s);      // { dg-warning "writing 1 or more bytes into a region of size 0" }
+  d = strcpy (a + i + 1, s);  // { dg-warning "writing 1 or more bytes into a region of size 0" }
+}
+
+void cpy_ul_1_max (unsigned long i, const char *s)
+{
+  if (i < 1) i = 1;
+  d = strcpy (a + i, s);      // { dg-warning "writing 1 or more bytes into a region of size 0" }
+  d = strcpy (a + i + 1, s);  // { dg-warning "writing 1 or more bytes into a region of size 0" "" { xfail *-*-* } }
+}
+
+
+void cpy_si_min_m1 (int i, const char *s)
+{
+  if (i > -1) i = -1;
+  d = strcpy (a + i - 1, s);  // { dg-warning "writing 1 or more bytes into a region of size 0" }
+  d = strcpy (a + i, s);      // { dg-warning "writing 1 or more bytes into a region of size 0" }
+  d = strcpy (a + i + 2, s);
+}
+
+void cpy_sl_min_m1 (long i, const char *s)
+{
+  if (i > -1) i = -1;
+  d = strcpy (a + i - 1, s);  // { dg-warning "writing 1 or more bytes into a region of size 0" }
+  d = strcpy (a + i, s);      // { dg-warning "writing 1 or more bytes into a region of size 0" }
+  d = strcpy (a + i + 2, s);
+}
index 2c5f4f05254c1e602d7915699e2f7a617c5efd7f..c615dae03fc31ce3e000c6cdf56775e7b9bcb2a2 100644 (file)
@@ -51,8 +51,8 @@ void test_memcpy_array (const void *s)
   T (a7 + UR (8, 9), s, 7);   /* { dg-warning "writing 7 bytes into a region of size 0" } */
 
   T (a7 + UR (9, 10), s, 7);  /* { dg-warning "writing 7 bytes into a region of size 0" } */
-  T (a7 + UR (DIFF_MAX, DIFF_MAX + (size_t)1), s, 7);  /* { dg-warning "writing 7 bytes into a region of size 0" "pr85350" { xfail *-*-* } } */
-  T (a7 + UR (DIFF_MAX, SIZE_MAX), s, 7);  /* { dg-warning "writing 7 bytes into a region of size 0" "pr85350" { xfail *-*-*} } */
+  T (a7 + UR (DIFF_MAX, DIFF_MAX + (size_t)1), s, 7);  /* { dg-warning "writing 7 bytes into a region of size 0" } */
+  T (a7 + UR (DIFF_MAX, SIZE_MAX), s, 7);  /* { dg-warning "writing 7 bytes into a region of size 0" } */
 
   /* This is valid.  */
   char *d = a7 + 7;
@@ -102,8 +102,8 @@ void test_strcpy_array (void)
   T (a7 + UR (8, 9), "012345");   /* { dg-warning "writing 7 bytes into a region of size 0" } */
 
   T (a7 + UR (9, 10), "012345");  /* { dg-warning "writing 7 bytes into a region of size 0" } */
-  T (a7 + UR (DIFF_MAX, DIFF_MAX + (size_t)1), "012345");  /* { dg-warning "writing 7 bytes into a region of size 0" "pr85350" { xfail *-*-* } } */
-  T (a7 + UR (DIFF_MAX, SIZE_MAX), "012345");  /* { dg-warning "writing 7 bytes into a region of size 0" "pr85350" { xfail *-*-* } } */
+  T (a7 + UR (DIFF_MAX, DIFF_MAX + (size_t)1), "012345");  /* { dg-warning "writing 7 bytes into a region of size 0" } */
+  T (a7 + UR (DIFF_MAX, SIZE_MAX), "012345");  /* { dg-warning "writing 7 bytes into a region of size 0" } */
 
   char *d = a7 + 7;
 
@@ -127,6 +127,6 @@ void test_strncpy_memarray (struct MemArray *p, const void *s)
   T (p->a9 + UR (9, 10), s, 9);   /* { dg-warning "writing 9 bytes into a region of size 0" } */
   T (p->a9 + UR (10, 11), s, 9);  /* { dg-warning "writing 9 bytes into a region of size 0" } */
 
-  T (p->a9 + UR (DIFF_MAX, DIFF_MAX + (size_t)1), s, 1);  /* { dg-warning "writing 1 byte into a region of size 0" "pr85350" { xfail *-*-* } } */
-  T (p->a9 + UR (DIFF_MAX, SIZE_MAX), s, 3);  /* { dg-warning "writing 3 bytes into a region of size 0" "pr85350" { xfail *-*-* } } */
+  T (p->a9 + UR (DIFF_MAX, DIFF_MAX + (size_t)1), s, 1);  /* { dg-warning "writing 1 byte into a region of size 0" } */
+  T (p->a9 + UR (DIFF_MAX, SIZE_MAX), s, 3);  /* { dg-warning "writing 3 bytes into a region of size 0" } */
 }
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overread-4.c b/gcc/testsuite/gcc.dg/Wstringop-overread-4.c
new file mode 100644 (file)
index 0000000..8248dad
--- /dev/null
@@ -0,0 +1,58 @@
+/* Verify -Wstringop-overread with a source pointer pointing either
+   before the beginning or past the end of an object.
+   { dg-do compile }
+   { dg-options "-O -Wall" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+size_t strlen (const char *);
+
+
+extern char a[1];
+
+volatile size_t n;
+
+void len_si_1_max (int i)
+{
+  if (i < 1) i = 1;
+  n = strlen (a + i);         // { dg-warning "reading 1 or more bytes from a region of size 0" }
+  n = strlen (a + i + 1);     // { dg-warning "reading 1 or more bytes from a region of size 0" }
+}
+
+void len_ui_1_max (unsigned i)
+{
+  if (i < 1) i = 1;
+  n = strlen (a + i);         // { dg-warning "reading 1 or more bytes from a region of size 0" }
+  n = strlen (a + i + 1);     // { dg-warning "reading 1 or more bytes from a region of size 0" "" { xfail ilp32 } }
+}
+
+void len_sl_1_max (long i)
+{
+  if (i < 1) i = 1;
+  n = strlen (a + i);         // { dg-warning "reading 1 or more bytes from a region of size 0" }
+  n = strlen (a + i + 1);     // { dg-warning "reading 1 or more bytes from a region of size 0" }
+}
+
+void len_ul_1_max (unsigned long i)
+{
+  if (i < 1) i = 1;
+  n = strlen (a + i);         // { dg-warning "reading 1 or more bytes from a region of size 0" }
+  n = strlen (a + i + 1);     // { dg-warning "reading 1 or more bytes from a region of size 0" "" { xfail *-*-* } }
+}
+
+
+void len_si_min_m1 (int i)
+{
+  if (i > -1) i = -1;
+  n = strlen (a + i - 1);     // { dg-warning "reading 1 or more bytes from a region of size 0" "" { xfail lp64 } }
+  n = strlen (a + i);         // { dg-warning "reading 1 or more bytes from a region of size 0" "" { xfail *-*-* } }
+  n = strlen (a + i + 2);
+}
+
+void len_sl_min_m1 (long i)
+{
+  if (i > -1) i = -1;
+  n = strlen (a + i - 1);     // { dg-warning "reading 1 or more bytes from a region of size 0" }
+  n = strlen (a + i);         // { dg-warning "reading 1 or more bytes from a region of size 0" "" { xfail *-*-* } }
+  n = strlen (a + i + 2);
+}