public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] correct -Wrestrict handling of arrays of arrays (PR 84095)
@ 2018-01-30 23:37 Martin Sebor
  2018-02-01 23:45 ` Martin Sebor
  0 siblings, 1 reply; 10+ messages in thread
From: Martin Sebor @ 2018-01-30 23:37 UTC (permalink / raw)
  To: Gcc Patch List

[-- Attachment #1: Type: text/plain, Size: 764 bytes --]

Testing GCC 8 with recent Linux kernel sources has uncovered
a bug in the handling of arrays of arrays by the -Wrestrict
checker where it fails to take references to different array
elements into consideration, issuing false positives.

The attached patch corrects this mistake.

In addition, to make warnings involving excessive offset bounds
more meaningful (less confusing), I've made a cosmetic change
to constrain them to the bounds of the accessed object.  I've
done this in response to multiple comments indicating that
the warnings are hard to interpret.  This change is meant to
be applied on top of the patch for bug 83698 (submitted mainly
to improve the readability of the offsets):

   https://gcc.gnu.org/ml/gcc-patches/2018-01/msg01488.html

Martin

[-- Attachment #2: gcc-84095.diff --]
[-- Type: text/x-patch, Size: 18369 bytes --]

PR middle-end/84095 - false-positive -Wrestrict warnings for memcpy within array

gcc/ChangeLog:

	PR middle-end/84095
	* gimple-ssa-warn-restrict.c (builtin_memref::builtin_memref): Handle
	inner references.

gcc/testsuite/ChangeLog:

	PR middle-end/84095
	* c-c++-common/Warray-bounds-3.c: Adjust text of expected warnings.
	* c-c++-common/Wrestrict.c: Same.
	* gcc.dg/Wrestrict-6.c: Same.
	* gcc.dg/Wrestrict-8.c: New test.

diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c
index 528eb5b..8bdf928 100644
--- a/gcc/gimple-ssa-warn-restrict.c
+++ b/gcc/gimple-ssa-warn-restrict.c
@@ -311,19 +311,40 @@ builtin_memref::builtin_memref (tree expr, tree size)
 
   if (TREE_CODE (expr) == ADDR_EXPR)
     {
-      poly_int64 off;
       tree op = TREE_OPERAND (expr, 0);
 
-      /* Determine the base object or pointer of the reference
-	 and its constant offset from the beginning of the base.  */
-      base = get_addr_base_and_unit_offset (op, &off);
+      /* Determine the base object or pointer of the reference and
+	 the constant bit offset from the beginning of the base.
+	 If the offset has a non-constant component, it will be in
+	 VAR_OFF.  MODE, SIGN, REVERSE, and VOL are write only and
+	 unused here.  */
+      poly_int64 bitsize, bitpos;
+      tree var_off;
+      machine_mode mode;
+      int sign, reverse, vol;
+      base = get_inner_reference (op, &bitsize, &bitpos, &var_off,
+				  &mode, &sign, &reverse, &vol);
+
+      poly_int64 bytepos = exact_div (bitpos, BITS_PER_UNIT);
 
       HOST_WIDE_INT const_off;
-      if (base && off.is_constant (&const_off))
+      if (base && bytepos.is_constant (&const_off))
 	{
 	  offrange[0] += const_off;
 	  offrange[1] += const_off;
 
+	  if (var_off)
+	    {
+	      if (TREE_CODE (var_off) == INTEGER_CST)
+		{
+		  offset_int cstoff = wi::to_offset (var_off);
+		  offrange[0] += cstoff;
+		  offrange[1] += cstoff;
+		}
+	      else
+		offrange[1] += maxobjsize;
+	    }
+
 	  /* Stash the reference for offset validation.  */
 	  ref = op;
 
@@ -375,12 +396,6 @@ builtin_memref::builtin_memref (tree expr, tree size)
 	    }
       }
 
-  if (DECL_P (base) && TREE_CODE (TREE_TYPE (base)) == ARRAY_TYPE)
-    {
-      if (offrange[0] < 0 && offrange[1] > 0)
-	offrange[0] = 0;
-    }
-
   if (size)
     {
       tree range[2];
@@ -396,6 +411,29 @@ builtin_memref::builtin_memref (tree expr, tree size)
     }
   else
     sizrange[1] = maxobjsize;
+
+  tree basetype = TREE_TYPE (base);
+  if (DECL_P (base) && TREE_CODE (basetype) == ARRAY_TYPE)
+    {
+      /* If the offset could be in range of the referenced object
+	 constrain its bounds so neither exceeds those of the obhect.  */
+      if (offrange[0] < 0 && offrange[1] > 0)
+	offrange[0] = 0;
+
+      offset_int maxoff = maxobjsize;
+      if (ref && array_at_struct_end_p (ref))
+	;   /* Use the maximum possible offset for last member arrays.  */
+      else if (tree basesize = TYPE_SIZE_UNIT (basetype))
+	maxoff = wi::to_offset (basesize);
+
+      if (offrange[0] >= 0)
+	{
+	  if (offrange[1] < 0)
+	    offrange[1] = offrange[0] <= maxoff ? maxoff : maxobjsize;
+	  else if (offrange[0] <= maxoff && offrange[1] > maxoff)
+	    offrange[1] = maxoff;
+	}
+    }
 }
 
 /* Return error_mark_node if the signed offset exceeds the bounds
diff --git a/gcc/testsuite/c-c++-common/Warray-bounds-3.c b/gcc/testsuite/c-c++-common/Warray-bounds-3.c
index 3445b95..2ee8146 100644
--- a/gcc/testsuite/c-c++-common/Warray-bounds-3.c
+++ b/gcc/testsuite/c-c++-common/Warray-bounds-3.c
@@ -61,7 +61,7 @@ void test_memcpy_bounds (char *d, const char *s, size_t n)
      they appear as large positive in the source.  It would be nice
      if they retained their type but unfortunately that's not how
      it works so be prepared for both in case it even gets fixed.  */
-  T (char, 1, a + UR (3, SIZE_MAX - 1), s, n);   /* { dg-warning "offset \\\[3, -2] is out of the bounds \\\[0, 1] of object" "memcpy" } */
+  T (char, 1, a + UR (3, SIZE_MAX - 1), s, n);   /* { dg-warning "offset \\\[3, -?\[0-9\]+] is out of the bounds \\\[0, 1] of object" "memcpy" } */
 
   /* Verify that invalid offsets into an array of unknown size are
      detected.  */
@@ -226,7 +226,7 @@ T (char, 1, a + SR (-2, -1), s, n);     /* { dg-warning "offset \\\[-2, -1] is o
      they appear as large positive in the source.  It would be nice
      if they retained their type but unfortunately that's not how
      it works so be prepared for both in case it ever gets fixed.  */
-  T (char, 1, a + UR (3, SIZE_MAX), s, n);   /* { dg-warning "offset \\\[3, -1] is out of the bounds \\\[0, 1] of object "  "mempcpy" } */
+  T (char, 1, a + UR (3, SIZE_MAX), s, n);   /* { dg-warning "offset \\\[3, -?\[0-9\]+] is out of the bounds \\\[0, 1] of object "  "mempcpy" } */
 
   /* Verify that invalid offsets into an array of unknown size are
      detected.  */
diff --git a/gcc/testsuite/c-c++-common/Wrestrict.c b/gcc/testsuite/c-c++-common/Wrestrict.c
index 72d9a47..22df9dd 100644
--- a/gcc/testsuite/c-c++-common/Wrestrict.c
+++ b/gcc/testsuite/c-c++-common/Wrestrict.c
@@ -223,7 +223,7 @@ void test_memcpy_range (char *d, size_t sz)
 
   /* Because the size is constant and a power of 2 the following is
      folded too early to detect the overlap.  */
-  T (d + ir, d, 4);               /* { dg-warning "accessing 4 bytes at offsets \\\[2, 3] and 0 overlaps 2 byte at offset 2" "" { xfail *-*-* } } */
+  T (d + ir, d, 4);               /* { dg-warning "accessing 4 bytes at offsets \\\[2, 3] and 0 overlaps 2 byte at offset 2" "memcpy" { xfail *-*-* } } */
   T (d + ir, d, 5);               /* { dg-warning "accessing 5 bytes at offsets \\\[2, 3] and 0 overlaps between 2 and 3 bytes at offset \\\[2, 3]" "memcpy" } */
 
   /* Exercise the full range of size_t.  */
@@ -325,11 +325,11 @@ void test_memcpy_anti_range (char *d, const char *s)
   T (d, d + SAR (0, 3), 1);
   T (d, d + SAR (0, 3), 2);
   T (d, d + SAR (0, 3), 3);
-  T (d, d + SAR (0, 3), DIFF_MAX - 2);   /* { dg-warning "overlaps \[0-9\]+ bytes at offset 2" } */
-  T (d, d + SAR (0, 3), DIFF_MAX - 1);   /* { dg-warning "overlaps \[0-9\]+ bytes at offset 1" } */
-  T (d, d + SAR (0, 3), DIFF_MAX);       /* { dg-warning "overlaps \[0-9\]+ bytes at offset 0" } */
+  T (d, d + SAR (0, 3), DIFF_MAX - 2);   /* { dg-warning "overlaps \[0-9\]+ bytes at offset 2" "memcpy" } */
+  T (d, d + SAR (0, 3), DIFF_MAX - 1);   /* { dg-warning "overlaps \[0-9\]+ bytes at offset 1" "memcpy" } */
+  T (d, d + SAR (0, 3), DIFF_MAX);       /* { dg-warning "overlaps \[0-9\]+ bytes at offset 0" "memcpy" } */
 
-  T (d, d + SAR (0, 3), UR (DIFF_MAX - 2, DIFF_MAX));               /* { dg-warning "accessing \[0-9\]+ or more bytes at offsets 0 and \\\[-?\[0-9\]+, -?\[0-9\]+] overlaps \[0-9\]+ bytes at offset 2" } */
+  T (d, d + SAR (0, 3), UR (DIFF_MAX - 2, DIFF_MAX));               /* { dg-warning "accessing \[0-9\]+ or more bytes at offsets 0 and \\\[-?\[0-9\]+, -?\[0-9\]+] overlaps \[0-9\]+ bytes at offset 2" "memcpy" } */
 
   /* Verify that a size in an anti-range ~[0, N] where N >= PTRDIFF_MAX
      doesn't trigger a warning.  */
@@ -398,8 +398,8 @@ void test_memcpy_range_exceed (char *d, const char *s)
   T (d, s + i, 5);   /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[9223372036854775805, 9223372036854775807] overlaps 3 bytes at offset 9223372036854775802" "LP64" { target lp64 } } */
   T (d + i, s, 5);   /* { dg-warning "accessing 5 bytes at offsets \\\[9223372036854775805, 9223372036854775807] and 0 overlaps 3 bytes at offset 9223372036854775802" "LP64" { target lp64 } } */
 #elif __SIZEOF_SIZE_T__ == 4
-  T (d, d + i, 5);   /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[2147483645, 2147483647] overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32 } } */
-  T (d + i, d, 5);   /* { dg-warning "accessing 5 bytes at offsets \\\[2147483645, 2147483647] and 0 overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32} } */
+  T (d, d + i, 5);   /* { dg-warning "accessing 5 bytes at offsets \\\[2147483645, 2147483647] and 0 overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32 } } */
+  T (d + i, d, 5);   /* { dg-warning "accessing 5 bytes at offsets \\\[2147483645, 2147483647] and 0 overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32 } } */
 
   T (d, s + i, 5);   /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[2147483645, 2147483647] overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32 } } */
   T (d + i, s, 5);   /* { dg-warning "accessing 5 bytes at offsets \\\[2147483645, 2147483647] and 0 overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32} } */
@@ -523,7 +523,7 @@ void test_memcpy_memarrray (struct MemArrays *p)
   T (p->a8, p->a8 + 2, 2);
   T (p->a8, p->a8 + 8, 1);
 
-  T (p->a8, p->a8 + 2, 3);        /* { dg-warning "accessing 3 bytes at offsets 0 and 2 overlaps 1 byte at offset 2" } */
+  T (p->a8, p->a8 + 2, 3);        /* { dg-warning "accessing 3 bytes at offsets 0 and 2 overlaps 1 byte at offset 2" "memcpy" } */
 }
 
 /* Exercise the absence of warnings with memmove.  */
@@ -768,13 +768,13 @@ void test_strcpy_range (void)
 
   /* The overlap in the cases below isn't inevitable but it is diagnosed
      because it is possible and so the code is considered unsafe.  */
-  T (8, "", a, a + r);               /* { dg-warning "accessing 1 byte may overlap 1 byte" "strcpy" } */
-  T (8, "0", a + r, a);              /* { dg-warning "accessing 2 bytes may overlap up to 2 bytes" "strcpy" } */
-  T (8, "012", a + r, a);            /* { dg-warning "accessing 4 bytes may overlap up to 4 bytes" "strcpy" } */
+  T (8, "", a, a + r);               /* { dg-warning "accessing 1 byte at offsets 0 and \\\[0, 8] may overlap 1 byte" "strcpy" } */
+  T (8, "0", a + r, a);              /* { dg-warning "accessing 2 bytes at offsets \\\[0, 8] and 0 may overlap up to 2 bytes" "strcpy" } */
+  T (8, "012", a + r, a);            /* { dg-warning "accessing 4 bytes at offsets \\\[0, 8] and 0 may overlap up to 4 bytes" "strcpy" } */
 
-  T (8, "", a, a + r);               /* { dg-warning "accessing 1 byte may overlap" "strcpy" } */
-  T (8, "0", a, a + r);              /* { dg-warning "accessing between 0 and 2 bytes may overlap up to 2 bytes" "strcpy" } */
-  T (8, "012", a, a + r);            /* { dg-warning "accessing between 0 and 4 bytes may overlap up to 4 bytes" "strcpy" } */
+  T (8, "", a, a + r);               /* { dg-warning "accessing 1 byte at offsets 0 and \\\[0, 8] may overlap" "strcpy" } */
+  T (8, "0", a, a + r);              /* { dg-warning "accessing between 0 and 2 bytes at offsets 0 and \\\[0, 8] may overlap up to 2 bytes" "strcpy" } */
+  T (8, "012", a, a + r);            /* { dg-warning "accessing between 0 and 4 bytes at offsets 0 and \\\[0, 8] may overlap up to 4 bytes" "strcpy" } */
 }
 
 /* Exercise strcpy with destination and/or source of unknown lengthu.  */
diff --git a/gcc/testsuite/gcc.dg/Wrestrict-6.c b/gcc/testsuite/gcc.dg/Wrestrict-6.c
index c1bb373..cc7185f 100644
--- a/gcc/testsuite/gcc.dg/Wrestrict-6.c
+++ b/gcc/testsuite/gcc.dg/Wrestrict-6.c
@@ -21,7 +21,7 @@ void warn_2_smax_p2 (void)
 
   ptrdiff_t i = UR (2, DIFF_MAX + (size_t)2);
 
-  strcpy (d, d + i);          /* { dg-warning "accessing between 0 and 4 bytes at offsets 0 and \\\[2, -\[0-9\]+] may overlap up to 2 bytes at offset 2" } */
+  strcpy (d, d + i);          /* { dg-warning "accessing between 0 and 4 bytes at offsets 0 and \\\[2, 7] may overlap up to 2 bytes at offset 2" } */
 
   sink (d);
 }
@@ -47,7 +47,7 @@ void warn_2u_smax_p2 (void)
 
   size_t i = UR (2, DIFF_MAX + (size_t)2);
 
-  strcpy (d, d + i);          /* { dg-warning "accessing between 0 and 4 bytes at offsets 0 and \\\[2, -\[0-9\]+] may overlap up to 2 bytes at offset 2" } */
+  strcpy (d, d + i);          /* { dg-warning "accessing between 0 and 4 bytes at offsets 0 and \\\[2, 7] may overlap up to 2 bytes at offset 2" } */
 
   sink (d);
 }
diff --git a/gcc/testsuite/gcc.dg/Wrestrict-8.c b/gcc/testsuite/gcc.dg/Wrestrict-8.c
new file mode 100644
index 0000000..24946b0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wrestrict-8.c
@@ -0,0 +1,116 @@
+/* PR tree-optimization/84095 - false-positive -Wrestrict warnings for
+   memcpy within array
+   { dg-do compile }
+   { dg-options "-O2 -Wrestrict -ftrack-macro-expansion=0" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern void* memcpy (void* restrict, const void* restrict, size_t);
+
+#define T(d, s, n)   memcpy (d, s, n)
+
+struct S1 { char c; } a8_1[8];
+
+void test_1_dim_var (int i, int j)
+{
+  /* Variable destination index and constant source index.  */
+  T (&a8_1[i], &a8_1[0], 1);
+  T (&a8_1[i], &a8_1[0], 2);
+  T (&a8_1[i], &a8_1[0], 3);
+  T (&a8_1[i], &a8_1[0], 4);
+
+  T (&a8_1[i], &a8_1[0], 5);    /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and 0 overlaps between 2 and 5 bytes at offset \\\[0, 3\\\]" } */
+  T (&a8_1[i], &a8_1[0], 6);    /* { dg-warning "accessing 6 bytes at offsets \\\[0, 8] and 0 overlaps between 4 and 6 bytes at offset \\\[0, 2\\\]" } */
+  T (&a8_1[i], &a8_1[0], 7);    /* { dg-warning "accessing 7 bytes at offsets \\\[0, 8] and 0 overlaps between 6 and 7 bytes at offset \\\[0, 1\\\]" } */
+  T (&a8_1[i], &a8_1[0], 8);    /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and 0 overlaps 8 bytes at offset 0" } */
+
+  /* The following is diagnosed by -Warray-bounds when it's enabled
+     rather than by -Wrestrict.  */
+  T (&a8_1[i], &a8_1[0], 9);    /* { dg-warning "accessing 9 bytes at offsets \\\[0, 8] and 0 overlaps 9 bytes at offset 0" } */
+
+  /* Same as above but with constant destination index and variable
+     source index.  */
+  T (&a8_1[0], &a8_1[i], 1);
+  T (&a8_1[0], &a8_1[i], 2);
+  T (&a8_1[0], &a8_1[i], 3);
+  T (&a8_1[0], &a8_1[i], 4);
+
+  T (&a8_1[0], &a8_1[i], 5);    /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[0, 8] overlaps between 2 and 5 bytes at offset \\\[0, 3\\\]" } */
+  T (&a8_1[0], &a8_1[i], 6);    /* { dg-warning "accessing 6 bytes at offsets 0 and \\\[0, 8] overlaps between 4 and 6 bytes at offset \\\[0, 2\\\]" } */
+  T (&a8_1[0], &a8_1[i], 7);    /* { dg-warning "accessing 7 bytes at offsets 0 and \\\[0, 8] overlaps between 6 and 7 bytes at offset \\\[0, 1\\\]" } */
+  T (&a8_1[0], &a8_1[i], 8);    /* { dg-warning "accessing 8 bytes at offsets 0 and \\\[0, 8] overlaps 8 bytes at offset 0" } */
+  T (&a8_1[0], &a8_1[i], 9);    /* { dg-warning "accessing 9 bytes at offsets 0 and \\\[0, 8] overlaps 9 bytes at offset 0" } */
+
+
+  /* Variable destination and source indices.  */
+  T (&a8_1[i], &a8_1[j], 1);
+  T (&a8_1[i], &a8_1[j], 2);
+  T (&a8_1[i], &a8_1[j], 3);
+  T (&a8_1[i], &a8_1[j], 4);
+
+  T (&a8_1[i], &a8_1[j], 5);    /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 2 and 5 bytes at offset \\\[0, 3\\\]" } */
+  T (&a8_1[i], &a8_1[j], 6);    /* { dg-warning "accessing 6 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 4 and 6 bytes at offset \\\[0, 2\\\]" } */
+  T (&a8_1[i], &a8_1[j], 7);    /* { dg-warning "accessing 7 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 6 and 7 bytes at offset \\\[0, 1\\\]" } */
+  T (&a8_1[i], &a8_1[j], 8);    /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps 8 bytes at offset 0" } */
+
+  /* The following is diagnosed by -Warray-bounds when it's enabled
+     rather than by -Wrestrict.  */
+  T (&a8_1[i], &a8_1[j], 9);    /* { dg-warning "accessing 9 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps 9 bytes at offset 0" } */
+}
+
+struct S4 { char a4[4]; } a2_4[2];
+
+void test_2_dim (int i, int j)
+{
+  T (&a2_4[i], &a2_4[0], 1);
+  T (&a2_4[i], &a2_4[0], 4);
+
+  T (&a2_4[i], &a2_4[0], 5);    /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and 0 overlaps between 2 and 5 bytes at offset \\\[0, 3]" } */
+  T (&a2_4[i], &a2_4[0], 6);    /* { dg-warning "accessing 6 bytes at offsets \\\[0, 8] and 0 overlaps between 4 and 6 bytes at offset \\\[0, 2]" } */
+  T (&a2_4[i], &a2_4[0], 7);    /* { dg-warning "accessing 7 bytes at offsets \\\[0, 8] and 0 overlaps between 6 and 7 bytes at offset \\\[0, 1]" } */
+  T (&a2_4[i], &a2_4[0], 8);    /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and 0 overlaps 8 bytes at offset 0" } */
+
+  T (a2_4[i].a4, a2_4[0].a4, 1);
+  T (a2_4[i].a4, a2_4[0].a4, 4);
+
+  T (a2_4[i].a4, a2_4[0].a4, 5);   /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and 0 overlaps between 2 and 5 bytes at offset \\\[0, 3]" } */
+  T (a2_4[i].a4, a2_4[0].a4, 8);   /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and 0 overlaps 8 bytes at offset 0" } */
+
+  T (a2_4[i].a4, a2_4[j].a4, 1);
+  T (a2_4[i].a4, a2_4[j].a4, 4);
+
+  /* The destination and source offsets printed below ignore the size
+     of the copy and only indicate the values that are valid for each
+     of the destination and source arguments on its own, without
+     considering the size of the overlapping access.  */
+  T (a2_4[i].a4, a2_4[j].a4, 5);   /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 2 and 5 bytes at offset \\\[0, 3]" } */
+  T (a2_4[i].a4, a2_4[j].a4, 8);   /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps 8 bytes at offset 0" } */
+
+  /* Same as above but referencing the first elements of each array.  */
+  T (&a2_4[i].a4[0], &a2_4[j].a4[0], 1);
+  T (&a2_4[i].a4[0], &a2_4[j].a4[0], 4);
+
+  T (&a2_4[i].a4[0], &a2_4[j].a4[0], 5);   /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 2 and 5 bytes at offset \\\[0, 3]" } */
+  T (&a2_4[i].a4[0], &a2_4[j].a4[0], 8);   /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps 8 bytes at offset 0" } */
+
+  T (&a2_4[i].a4[0], &a2_4[j].a4[1], 3);
+  T (&a2_4[i].a4[0], &a2_4[j].a4[2], 2);
+  T (&a2_4[i].a4[0], &a2_4[j].a4[3], 1);
+}
+
+struct { int i; } a2[2][8];
+
+void test_single_2_dim_major (int i)
+{
+  memcpy (&a2[i], &a2[0], sizeof *a2);   /* { dg-bogus "\\\[-Wrestrict]" } */
+}
+
+void test_single_2_dim_minor (int i)
+{
+  memcpy (&a2[i][0], &a2[0][0], sizeof a2[0][0]);   /* { dg-bogus "\\\[-Wrestrict]" } */
+}
+
+void test_single_2_dim_major_minor (int i, int j)
+{
+  memcpy (&a2[i][j], &a2[0][0], sizeof a2[0][0]);   /* { dg-bogus "\\\[-Wrestrict]" } */
+}

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] correct -Wrestrict handling of arrays of arrays (PR 84095)
  2018-01-30 23:37 [PATCH] correct -Wrestrict handling of arrays of arrays (PR 84095) Martin Sebor
@ 2018-02-01 23:45 ` Martin Sebor
  2018-02-09  2:46   ` Martin Sebor
                     ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Martin Sebor @ 2018-02-01 23:45 UTC (permalink / raw)
  To: Gcc Patch List, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 1993 bytes --]

The previous patch didn't resolve all the false positives
in the Linux kernel.  The attached is an update that fixes
the remaining one having to do with multidimensional array
members:

   struct S { char a[2][4]; };

   void f (struct S *p, int i)
   {
     strcpy (p->a[0], "012");
     strcpy (p->a[i] + 1, p->a[0]);   // false positive here
   }

In the process of fixing this I also made a couple of minor
restructuring changes to the builtin_memref constructor to
in order to make the code easier to follow: I broke it out
into a couple of helper functions and called those.

As with the first revision of the patch, this one is also
meant to be applied on top of

   https://gcc.gnu.org/ml/gcc-patches/2018-01/msg01488.html

Sorry about the late churn.  Even though I tested the original
implementation with the Linux kernel the bugs were only exposed
non-default configurations that I didn't build.

Jakub, you had concerns about the code in the constructor
and about interpreting the offsets in the diagnostics.
I tried to address those in the patch.  Please review
the changes and let me know if you have any further comments.

Thanks
Martin

On 01/30/2018 04:19 PM, Martin Sebor wrote:
> Testing GCC 8 with recent Linux kernel sources has uncovered
> a bug in the handling of arrays of arrays by the -Wrestrict
> checker where it fails to take references to different array
> elements into consideration, issuing false positives.
>
> The attached patch corrects this mistake.
>
> In addition, to make warnings involving excessive offset bounds
> more meaningful (less confusing), I've made a cosmetic change
> to constrain them to the bounds of the accessed object.  I've
> done this in response to multiple comments indicating that
> the warnings are hard to interpret.  This change is meant to
> be applied on top of the patch for bug 83698 (submitted mainly
> to improve the readability of the offsets):
>
>   https://gcc.gnu.org/ml/gcc-patches/2018-01/msg01488.html
>
> Martin


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: gcc-84095.diff --]
[-- Type: text/x-patch; name="gcc-84095.diff", Size: 35957 bytes --]

PR middle-end/84095 - false-positive -Wrestrict warnings for memcpy within array

gcc/ChangeLog:

	PR middle-end/84095
	* gimple-ssa-warn-restrict.c (builtin_memref::extend_offset_range): New.
	(builtin_memref::set_base_and_offset): Same.  Handle inner references.
	(builtin_memref::builtin_memref): Factor out parts into
	set_base_and_offset and call it.

gcc/testsuite/ChangeLog:

	PR middle-end/84095
	* c-c++-common/Warray-bounds-3.c: Adjust text of expected warnings.
	* c-c++-common/Wrestrict.c: Same.
	* gcc.dg/Wrestrict-6.c: Same.
	* gcc.dg/Warray-bounds-27.c: New test.
	* gcc.dg/Wrestrict-8.c: New test.
	* gcc.dg/Wrestrict-9.c: New test.
	* gcc.dg/pr84095.c: New test.

diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c
index 528eb5b..367e05f 100644
--- a/gcc/gimple-ssa-warn-restrict.c
+++ b/gcc/gimple-ssa-warn-restrict.c
@@ -158,6 +158,14 @@ struct builtin_memref
   builtin_memref (tree, tree);
 
   tree offset_out_of_bounds (int, offset_int[2]) const;
+
+private:
+
+  /* Ctor helper to set or extend OFFRANGE based on argument.  */
+  void extend_offset_range (tree);
+
+  /*  Ctor helper to determine BASE and OFFRANGE from argument.  */
+  void set_base_and_offset (tree);
 };
 
 /* Description of a memory access by a raw memory or string built-in
@@ -214,6 +222,7 @@ class builtin_access
   bool (builtin_access::*detect_overlap) ();
 };
 
+
 /* Initialize a memory reference representation from a pointer EXPR and
    a size SIZE in bytes.  If SIZE is NULL_TREE then the size is assumed
    to be unknown.  */
@@ -235,11 +244,120 @@ builtin_memref::builtin_memref (tree expr, tree size)
 
   const offset_int maxobjsize = tree_to_shwi (max_object_size ());
 
+  /* Find the BASE object or pointer referenced by EXPR and set
+     the offset range OFFRANGE in the process.  */
+  set_base_and_offset (expr);
+
+  if (size)
+    {
+      tree range[2];
+      /* Determine the size range, allowing for the result to be [0, 0]
+	 for SIZE in the anti-range ~[0, N] where N >= PTRDIFF_MAX.  */
+      get_size_range (size, range, true);
+      sizrange[0] = wi::to_offset (range[0]);
+      sizrange[1] = wi::to_offset (range[1]);
+      /* get_size_range returns SIZE_MAX for the maximum size.
+	 Constrain it to the real maximum of PTRDIFF_MAX.  */
+      if (sizrange[1] > maxobjsize)
+	sizrange[1] = maxobjsize;
+    }
+  else
+    sizrange[1] = maxobjsize;
+
+  tree basetype = TREE_TYPE (base);
+  if (DECL_P (base) && TREE_CODE (basetype) == ARRAY_TYPE)
+    {
+      /* If the offset could be in range of the referenced object
+	 constrain its bounds so neither exceeds those of the object.  */
+      if (offrange[0] < 0 && offrange[1] > 0)
+	offrange[0] = 0;
+
+      offset_int maxoff = maxobjsize;
+      if (ref && array_at_struct_end_p (ref))
+	;   /* Use the maximum possible offset for last member arrays.  */
+      else if (tree basesize = TYPE_SIZE_UNIT (basetype))
+	maxoff = wi::to_offset (basesize);
+
+      if (offrange[0] >= 0)
+	{
+	  if (offrange[1] < 0)
+	    offrange[1] = offrange[0] <= maxoff ? maxoff : maxobjsize;
+	  else if (offrange[0] <= maxoff && offrange[1] > maxoff)
+	    offrange[1] = maxoff;
+	}
+    }
+}
+
+/* Ctor helper to set or extend OFFRANGE based on the OFFSET argument.  */
+
+void
+builtin_memref::extend_offset_range (tree offset)
+{
+  const offset_int maxobjsize = tree_to_shwi (max_object_size ());
+
+  if (TREE_CODE (offset) == INTEGER_CST)
+    {
+      offset_int off = int_cst_value (offset);
+      if (off != 0)
+	{
+	  offrange[0] += off;
+	  offrange[1] += off;
+	}
+      return;
+    }
+
+  if (TREE_CODE (offset) == SSA_NAME)
+    {
+      wide_int min, max;
+      value_range_type rng = get_range_info (offset, &min, &max);
+      if (rng == VR_RANGE)
+	{
+	  offrange[0] += offset_int::from (min, SIGNED);
+	  offrange[1] += offset_int::from (max, SIGNED);
+	}
+      else if (rng == VR_ANTI_RANGE)
+	{
+	  offrange[0] += offset_int::from (max + 1, SIGNED);
+	  offrange[1] += offset_int::from (min - 1, SIGNED);
+	}
+      else
+	{
+	  gimple *stmt = SSA_NAME_DEF_STMT (offset);
+	  tree type;
+	  if (is_gimple_assign (stmt)
+	      && gimple_assign_rhs_code (stmt) == NOP_EXPR
+	      && (type = TREE_TYPE (gimple_assign_rhs1 (stmt)))
+	      && INTEGRAL_TYPE_P (type))
+	    {
+	      /* Use the bounds of the type of the NOP_EXPR operand
+		 even if it's signed.  The result doesn't trigger
+		 warnings but makes their output more readable.  */
+	      offrange[0] += wi::to_offset (TYPE_MIN_VALUE (type));
+	      offrange[1] += wi::to_offset (TYPE_MAX_VALUE (type));
+	    }
+	  else
+	    offrange[1] += maxobjsize;
+	}
+      return;
+    }
+
+  offrange[1] += maxobjsize;
+}
+
+/* Determines the base object or pointer of the reference EXPR
+   and the offset range from the beginning of the base.  */
+
+void
+builtin_memref::set_base_and_offset (tree expr)
+{
+  const offset_int maxobjsize = tree_to_shwi (max_object_size ());
+
   if (TREE_CODE (expr) == SSA_NAME)
     {
       /* Try to tease the offset out of the pointer.  */
       gimple *stmt = SSA_NAME_DEF_STMT (expr);
-      if (gimple_assign_single_p (stmt)
+      if (!base
+	  && gimple_assign_single_p (stmt)
 	  && gimple_assign_rhs_code (stmt) == ADDR_EXPR)
 	expr = gimple_assign_rhs1 (stmt);
       else if (is_gimple_assign (stmt))
@@ -250,152 +368,90 @@ builtin_memref::builtin_memref (tree expr, tree size)
 	      tree rhs = gimple_assign_rhs1 (stmt);
 	      if (POINTER_TYPE_P (TREE_TYPE (rhs)))
 		expr = gimple_assign_rhs1 (stmt);
+	      else
+		{
+		  base = expr;
+		  return;
+		}
 	    }
 	  else if (code == POINTER_PLUS_EXPR)
 	    {
 	      expr = gimple_assign_rhs1 (stmt);
 
 	      tree offset = gimple_assign_rhs2 (stmt);
-	      if (TREE_CODE (offset) == INTEGER_CST)
-		{
-		  offset_int off = int_cst_value (offset);
-		  offrange[0] = off;
-		  offrange[1] = off;
-
-		  if (TREE_CODE (expr) == SSA_NAME)
-		    {
-		      gimple *stmt = SSA_NAME_DEF_STMT (expr);
-		      if (gimple_assign_single_p (stmt)
-			  && gimple_assign_rhs_code (stmt) == ADDR_EXPR)
-			expr = gimple_assign_rhs1 (stmt);
-		    }
-		}
-	      else if (TREE_CODE (offset) == SSA_NAME)
-		{
-		  wide_int min, max;
-		  value_range_type rng = get_range_info (offset, &min, &max);
-		  if (rng == VR_RANGE)
-		    {
-		      offrange[0] = offset_int::from (min, SIGNED);
-		      offrange[1] = offset_int::from (max, SIGNED);
-		    }
-		  else if (rng == VR_ANTI_RANGE)
-		    {
-		      offrange[0] = offset_int::from (max + 1, SIGNED);
-		      offrange[1] = offset_int::from (min - 1, SIGNED);
-		    }
-		  else
-		    {
-		      gimple *stmt = SSA_NAME_DEF_STMT (offset);
-		      tree type;
-		      if (is_gimple_assign (stmt)
-			  && gimple_assign_rhs_code (stmt) == NOP_EXPR
-			  && (type = TREE_TYPE (gimple_assign_rhs1 (stmt)))
-			  && INTEGRAL_TYPE_P (type))
-			{
-			  /* Use the bounds of the type of the NOP_EXPR operand
-			     even if it's signed.  The result doesn't trigger
-			     warnings but makes their output more readable.  */
-			  offrange[0] = wi::to_offset (TYPE_MIN_VALUE (type));
-			  offrange[1] = wi::to_offset (TYPE_MAX_VALUE (type));
-			}
-		      else
-			offrange[1] = maxobjsize;
-		    }
-		}
-	      else
-		offrange[1] = maxobjsize;
+	      extend_offset_range (offset);
 	    }
+	  else
+	    {
+	      base = expr;
+	      return;
+	    }
+	}
+      else if (gimple_nop_p (stmt))
+	expr = SSA_NAME_VAR (expr);
+      else
+	{
+	  base = expr;
+	  return;
 	}
     }
 
   if (TREE_CODE (expr) == ADDR_EXPR)
-    {
-      poly_int64 off;
-      tree op = TREE_OPERAND (expr, 0);
+    expr = TREE_OPERAND (expr, 0);
 
-      /* Determine the base object or pointer of the reference
-	 and its constant offset from the beginning of the base.  */
-      base = get_addr_base_and_unit_offset (op, &off);
+  poly_int64 bitsize, bitpos;
+  tree var_off;
+  machine_mode mode;
+  int sign, reverse, vol;
 
-      HOST_WIDE_INT const_off;
-      if (base && off.is_constant (&const_off))
-	{
-	  offrange[0] += const_off;
-	  offrange[1] += const_off;
+  /* Determine the base object or pointer of the reference and
+     the constant bit offset from the beginning of the base.
+     If the offset has a non-constant component, it will be in
+     VAR_OFF.  MODE, SIGN, REVERSE, and VOL are write only and
+     unused here.  */
+  base = get_inner_reference (expr, &bitsize, &bitpos, &var_off,
+			      &mode, &sign, &reverse, &vol);
 
-	  /* Stash the reference for offset validation.  */
-	  ref = op;
+  poly_int64 bytepos = exact_div (bitpos, BITS_PER_UNIT);
 
-	  /* Also stash the constant offset for offset validation.  */
-	  if (TREE_CODE (op) == COMPONENT_REF)
-	    refoff = const_off;
-	}
-      else
-	{
-	  size = NULL_TREE;
-	  base = get_base_address (TREE_OPERAND (expr, 0));
-	}
+  HOST_WIDE_INT const_off;
+  if (!base || !bytepos.is_constant (&const_off))
+    {
+      base = get_base_address (TREE_OPERAND (expr, 0));
+      return;
     }
 
-  if (!base)
-    base = build2 (MEM_REF, char_type_node, expr, null_pointer_node);
+  offrange[0] += const_off;
+  offrange[1] += const_off;
 
-  if (TREE_CODE (base) == MEM_REF)
+  if (var_off)
     {
-      offset_int off;
-      if (mem_ref_offset (base).is_constant (&off))
+      if (TREE_CODE (var_off) == INTEGER_CST)
 	{
-	  refoff += off;
-	  offrange[0] += off;
-	  offrange[1] += off;
+	  offset_int cstoff = wi::to_offset (var_off);
+	  offrange[0] += cstoff;
+	  offrange[1] += cstoff;
 	}
       else
-	size = NULL_TREE;
-      base = TREE_OPERAND (base, 0);
+	offrange[1] += maxobjsize;
     }
 
-  if (TREE_CODE (base) == SSA_NAME)
-    if (gimple *stmt = SSA_NAME_DEF_STMT (base))
-      {
-	enum gimple_code code = gimple_code (stmt);
-	if (code == GIMPLE_ASSIGN)
-	  if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
-	    {
-	      base = gimple_assign_rhs1 (stmt);
+  /* Stash the reference for offset validation.  */
+  ref = expr;
 
-	      tree offset = gimple_assign_rhs2 (stmt);
-	      if (TREE_CODE (offset) == INTEGER_CST)
-		{
-		  offset_int off = int_cst_value (offset);
-		  refoff += off;
-		  offrange[0] += off;
-		  offrange[1] += off;
-		}
-	    }
-      }
+  /* Also stash the constant offset for offset validation.  */
+  if (TREE_CODE (expr) == COMPONENT_REF)
+    refoff = const_off;
 
-  if (DECL_P (base) && TREE_CODE (TREE_TYPE (base)) == ARRAY_TYPE)
+  if (TREE_CODE (base) == MEM_REF)
     {
-      if (offrange[0] < 0 && offrange[1] > 0)
-	offrange[0] = 0;
+      tree memrefoff = TREE_OPERAND (base, 1);
+      extend_offset_range (memrefoff);
+      base = TREE_OPERAND (base, 0);
     }
 
-  if (size)
-    {
-      tree range[2];
-      /* Determine the size range, allowing for the result to be [0, 0]
-	 for SIZE in the anti-range ~[0, N] where N >= PTRDIFF_MAX.  */
-      get_size_range (size, range, true);
-      sizrange[0] = wi::to_offset (range[0]);
-      sizrange[1] = wi::to_offset (range[1]);
-      /* get_size_range returns SIZE_MAX for the maximum size.
-	 Constrain it to the real maximum of PTRDIFF_MAX.  */
-      if (sizrange[1] > maxobjsize)
-	sizrange[1] = maxobjsize;
-    }
-  else
-    sizrange[1] = maxobjsize;
+  if (TREE_CODE (base) == SSA_NAME)
+    set_base_and_offset (base);
 }
 
 /* Return error_mark_node if the signed offset exceeds the bounds
@@ -862,10 +918,18 @@ builtin_access::generic_overlap ()
      the other.  */
   bool depends_p = detect_overlap != &builtin_access::generic_overlap;
 
-  if (!overlap_certain
-      && !dstref->strbounded_p
-      && !depends_p)
-    return false;
+  if (!overlap_certain)
+    {
+      if (!dstref->strbounded_p && !depends_p)
+	return false;
+
+      /* There's no way to distinguish an access to the same member
+	 of a structure from one to two distinct members of the same
+	 structure.  Give up to avoid excessive false positives.  */
+      tree basetype = TREE_TYPE (TREE_TYPE (dstref->base));
+      if (RECORD_OR_UNION_TYPE_P (basetype))
+	return false;
+    }
 
   /* True for stpcpy and strcpy.  */
   bool stxcpy_p = (!dstref->strbounded_p
diff --git a/gcc/testsuite/c-c++-common/Warray-bounds-3.c b/gcc/testsuite/c-c++-common/Warray-bounds-3.c
index 3445b95..2ee8146 100644
--- a/gcc/testsuite/c-c++-common/Warray-bounds-3.c
+++ b/gcc/testsuite/c-c++-common/Warray-bounds-3.c
@@ -61,7 +61,7 @@ void test_memcpy_bounds (char *d, const char *s, size_t n)
      they appear as large positive in the source.  It would be nice
      if they retained their type but unfortunately that's not how
      it works so be prepared for both in case it even gets fixed.  */
-  T (char, 1, a + UR (3, SIZE_MAX - 1), s, n);   /* { dg-warning "offset \\\[3, -2] is out of the bounds \\\[0, 1] of object" "memcpy" } */
+  T (char, 1, a + UR (3, SIZE_MAX - 1), s, n);   /* { dg-warning "offset \\\[3, -?\[0-9\]+] is out of the bounds \\\[0, 1] of object" "memcpy" } */
 
   /* Verify that invalid offsets into an array of unknown size are
      detected.  */
@@ -226,7 +226,7 @@ T (char, 1, a + SR (-2, -1), s, n);     /* { dg-warning "offset \\\[-2, -1] is o
      they appear as large positive in the source.  It would be nice
      if they retained their type but unfortunately that's not how
      it works so be prepared for both in case it ever gets fixed.  */
-  T (char, 1, a + UR (3, SIZE_MAX), s, n);   /* { dg-warning "offset \\\[3, -1] is out of the bounds \\\[0, 1] of object "  "mempcpy" } */
+  T (char, 1, a + UR (3, SIZE_MAX), s, n);   /* { dg-warning "offset \\\[3, -?\[0-9\]+] is out of the bounds \\\[0, 1] of object "  "mempcpy" } */
 
   /* Verify that invalid offsets into an array of unknown size are
      detected.  */
diff --git a/gcc/testsuite/c-c++-common/Wrestrict.c b/gcc/testsuite/c-c++-common/Wrestrict.c
index 72d9a47..22df9dd 100644
--- a/gcc/testsuite/c-c++-common/Wrestrict.c
+++ b/gcc/testsuite/c-c++-common/Wrestrict.c
@@ -223,7 +223,7 @@ void test_memcpy_range (char *d, size_t sz)
 
   /* Because the size is constant and a power of 2 the following is
      folded too early to detect the overlap.  */
-  T (d + ir, d, 4);               /* { dg-warning "accessing 4 bytes at offsets \\\[2, 3] and 0 overlaps 2 byte at offset 2" "" { xfail *-*-* } } */
+  T (d + ir, d, 4);               /* { dg-warning "accessing 4 bytes at offsets \\\[2, 3] and 0 overlaps 2 byte at offset 2" "memcpy" { xfail *-*-* } } */
   T (d + ir, d, 5);               /* { dg-warning "accessing 5 bytes at offsets \\\[2, 3] and 0 overlaps between 2 and 3 bytes at offset \\\[2, 3]" "memcpy" } */
 
   /* Exercise the full range of size_t.  */
@@ -325,11 +325,11 @@ void test_memcpy_anti_range (char *d, const char *s)
   T (d, d + SAR (0, 3), 1);
   T (d, d + SAR (0, 3), 2);
   T (d, d + SAR (0, 3), 3);
-  T (d, d + SAR (0, 3), DIFF_MAX - 2);   /* { dg-warning "overlaps \[0-9\]+ bytes at offset 2" } */
-  T (d, d + SAR (0, 3), DIFF_MAX - 1);   /* { dg-warning "overlaps \[0-9\]+ bytes at offset 1" } */
-  T (d, d + SAR (0, 3), DIFF_MAX);       /* { dg-warning "overlaps \[0-9\]+ bytes at offset 0" } */
+  T (d, d + SAR (0, 3), DIFF_MAX - 2);   /* { dg-warning "overlaps \[0-9\]+ bytes at offset 2" "memcpy" } */
+  T (d, d + SAR (0, 3), DIFF_MAX - 1);   /* { dg-warning "overlaps \[0-9\]+ bytes at offset 1" "memcpy" } */
+  T (d, d + SAR (0, 3), DIFF_MAX);       /* { dg-warning "overlaps \[0-9\]+ bytes at offset 0" "memcpy" } */
 
-  T (d, d + SAR (0, 3), UR (DIFF_MAX - 2, DIFF_MAX));               /* { dg-warning "accessing \[0-9\]+ or more bytes at offsets 0 and \\\[-?\[0-9\]+, -?\[0-9\]+] overlaps \[0-9\]+ bytes at offset 2" } */
+  T (d, d + SAR (0, 3), UR (DIFF_MAX - 2, DIFF_MAX));               /* { dg-warning "accessing \[0-9\]+ or more bytes at offsets 0 and \\\[-?\[0-9\]+, -?\[0-9\]+] overlaps \[0-9\]+ bytes at offset 2" "memcpy" } */
 
   /* Verify that a size in an anti-range ~[0, N] where N >= PTRDIFF_MAX
      doesn't trigger a warning.  */
@@ -398,8 +398,8 @@ void test_memcpy_range_exceed (char *d, const char *s)
   T (d, s + i, 5);   /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[9223372036854775805, 9223372036854775807] overlaps 3 bytes at offset 9223372036854775802" "LP64" { target lp64 } } */
   T (d + i, s, 5);   /* { dg-warning "accessing 5 bytes at offsets \\\[9223372036854775805, 9223372036854775807] and 0 overlaps 3 bytes at offset 9223372036854775802" "LP64" { target lp64 } } */
 #elif __SIZEOF_SIZE_T__ == 4
-  T (d, d + i, 5);   /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[2147483645, 2147483647] overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32 } } */
-  T (d + i, d, 5);   /* { dg-warning "accessing 5 bytes at offsets \\\[2147483645, 2147483647] and 0 overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32} } */
+  T (d, d + i, 5);   /* { dg-warning "accessing 5 bytes at offsets \\\[2147483645, 2147483647] and 0 overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32 } } */
+  T (d + i, d, 5);   /* { dg-warning "accessing 5 bytes at offsets \\\[2147483645, 2147483647] and 0 overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32 } } */
 
   T (d, s + i, 5);   /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[2147483645, 2147483647] overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32 } } */
   T (d + i, s, 5);   /* { dg-warning "accessing 5 bytes at offsets \\\[2147483645, 2147483647] and 0 overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32} } */
@@ -523,7 +523,7 @@ void test_memcpy_memarrray (struct MemArrays *p)
   T (p->a8, p->a8 + 2, 2);
   T (p->a8, p->a8 + 8, 1);
 
-  T (p->a8, p->a8 + 2, 3);        /* { dg-warning "accessing 3 bytes at offsets 0 and 2 overlaps 1 byte at offset 2" } */
+  T (p->a8, p->a8 + 2, 3);        /* { dg-warning "accessing 3 bytes at offsets 0 and 2 overlaps 1 byte at offset 2" "memcpy" } */
 }
 
 /* Exercise the absence of warnings with memmove.  */
@@ -768,13 +768,13 @@ void test_strcpy_range (void)
 
   /* The overlap in the cases below isn't inevitable but it is diagnosed
      because it is possible and so the code is considered unsafe.  */
-  T (8, "", a, a + r);               /* { dg-warning "accessing 1 byte may overlap 1 byte" "strcpy" } */
-  T (8, "0", a + r, a);              /* { dg-warning "accessing 2 bytes may overlap up to 2 bytes" "strcpy" } */
-  T (8, "012", a + r, a);            /* { dg-warning "accessing 4 bytes may overlap up to 4 bytes" "strcpy" } */
+  T (8, "", a, a + r);               /* { dg-warning "accessing 1 byte at offsets 0 and \\\[0, 8] may overlap 1 byte" "strcpy" } */
+  T (8, "0", a + r, a);              /* { dg-warning "accessing 2 bytes at offsets \\\[0, 8] and 0 may overlap up to 2 bytes" "strcpy" } */
+  T (8, "012", a + r, a);            /* { dg-warning "accessing 4 bytes at offsets \\\[0, 8] and 0 may overlap up to 4 bytes" "strcpy" } */
 
-  T (8, "", a, a + r);               /* { dg-warning "accessing 1 byte may overlap" "strcpy" } */
-  T (8, "0", a, a + r);              /* { dg-warning "accessing between 0 and 2 bytes may overlap up to 2 bytes" "strcpy" } */
-  T (8, "012", a, a + r);            /* { dg-warning "accessing between 0 and 4 bytes may overlap up to 4 bytes" "strcpy" } */
+  T (8, "", a, a + r);               /* { dg-warning "accessing 1 byte at offsets 0 and \\\[0, 8] may overlap" "strcpy" } */
+  T (8, "0", a, a + r);              /* { dg-warning "accessing between 0 and 2 bytes at offsets 0 and \\\[0, 8] may overlap up to 2 bytes" "strcpy" } */
+  T (8, "012", a, a + r);            /* { dg-warning "accessing between 0 and 4 bytes at offsets 0 and \\\[0, 8] may overlap up to 4 bytes" "strcpy" } */
 }
 
 /* Exercise strcpy with destination and/or source of unknown lengthu.  */
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..cdbb192
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-27.c
@@ -0,0 +1,35 @@
+/* { dg-do compile }
+   { dg-options "-O2 -Wall -Wextra -Warray-bounds -Wrestrict" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern void* memcpy (void* restrict, const void* restrict, size_t);
+
+extern void sink (void*, ...);
+
+struct Data {
+  size_t n;
+  void *p;
+};
+
+void test_copy (void)
+{
+  struct Data d;
+  sink (&d);
+
+  char dp1[sizeof d + 1];
+  char d2x[2 * sizeof d];
+  char d2xp1[2 * sizeof d + 1];
+
+  /* During development the following would incorrectly trigger:
+     warning: 'memcpy' forming offset [17, 25] is out of the bounds [0, 16]
+              of object ‘d’ with type 'struct Data' [-Warray-bounds]
+     that wasn't caught by the test suite.  Make sure it is.  */
+  memcpy (&dp1, d.p, sizeof dp1);       /* { dg-bogus "\\\[-Warray-bounds" } */
+
+  /* Likewise.  */
+  memcpy (&d2x, d.p, sizeof d2x);       /* { dg-bogus "\\\[-Warray-bounds" } */
+  memcpy (&d2xp1, d.p, sizeof d2xp1);   /* { dg-bogus "\\\[-Warray-bounds" } */
+
+  sink (&d, &dp1, &d2x, &d2xp1);
+}
diff --git a/gcc/testsuite/gcc.dg/Wrestrict-6.c b/gcc/testsuite/gcc.dg/Wrestrict-6.c
index c1bb373..cc7185f 100644
--- a/gcc/testsuite/gcc.dg/Wrestrict-6.c
+++ b/gcc/testsuite/gcc.dg/Wrestrict-6.c
@@ -21,7 +21,7 @@ void warn_2_smax_p2 (void)
 
   ptrdiff_t i = UR (2, DIFF_MAX + (size_t)2);
 
-  strcpy (d, d + i);          /* { dg-warning "accessing between 0 and 4 bytes at offsets 0 and \\\[2, -\[0-9\]+] may overlap up to 2 bytes at offset 2" } */
+  strcpy (d, d + i);          /* { dg-warning "accessing between 0 and 4 bytes at offsets 0 and \\\[2, 7] may overlap up to 2 bytes at offset 2" } */
 
   sink (d);
 }
@@ -47,7 +47,7 @@ void warn_2u_smax_p2 (void)
 
   size_t i = UR (2, DIFF_MAX + (size_t)2);
 
-  strcpy (d, d + i);          /* { dg-warning "accessing between 0 and 4 bytes at offsets 0 and \\\[2, -\[0-9\]+] may overlap up to 2 bytes at offset 2" } */
+  strcpy (d, d + i);          /* { dg-warning "accessing between 0 and 4 bytes at offsets 0 and \\\[2, 7] may overlap up to 2 bytes at offset 2" } */
 
   sink (d);
 }
diff --git a/gcc/testsuite/gcc.dg/Wrestrict-8.c b/gcc/testsuite/gcc.dg/Wrestrict-8.c
new file mode 100644
index 0000000..24946b0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wrestrict-8.c
@@ -0,0 +1,116 @@
+/* PR tree-optimization/84095 - false-positive -Wrestrict warnings for
+   memcpy within array
+   { dg-do compile }
+   { dg-options "-O2 -Wrestrict -ftrack-macro-expansion=0" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern void* memcpy (void* restrict, const void* restrict, size_t);
+
+#define T(d, s, n)   memcpy (d, s, n)
+
+struct S1 { char c; } a8_1[8];
+
+void test_1_dim_var (int i, int j)
+{
+  /* Variable destination index and constant source index.  */
+  T (&a8_1[i], &a8_1[0], 1);
+  T (&a8_1[i], &a8_1[0], 2);
+  T (&a8_1[i], &a8_1[0], 3);
+  T (&a8_1[i], &a8_1[0], 4);
+
+  T (&a8_1[i], &a8_1[0], 5);    /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and 0 overlaps between 2 and 5 bytes at offset \\\[0, 3\\\]" } */
+  T (&a8_1[i], &a8_1[0], 6);    /* { dg-warning "accessing 6 bytes at offsets \\\[0, 8] and 0 overlaps between 4 and 6 bytes at offset \\\[0, 2\\\]" } */
+  T (&a8_1[i], &a8_1[0], 7);    /* { dg-warning "accessing 7 bytes at offsets \\\[0, 8] and 0 overlaps between 6 and 7 bytes at offset \\\[0, 1\\\]" } */
+  T (&a8_1[i], &a8_1[0], 8);    /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and 0 overlaps 8 bytes at offset 0" } */
+
+  /* The following is diagnosed by -Warray-bounds when it's enabled
+     rather than by -Wrestrict.  */
+  T (&a8_1[i], &a8_1[0], 9);    /* { dg-warning "accessing 9 bytes at offsets \\\[0, 8] and 0 overlaps 9 bytes at offset 0" } */
+
+  /* Same as above but with constant destination index and variable
+     source index.  */
+  T (&a8_1[0], &a8_1[i], 1);
+  T (&a8_1[0], &a8_1[i], 2);
+  T (&a8_1[0], &a8_1[i], 3);
+  T (&a8_1[0], &a8_1[i], 4);
+
+  T (&a8_1[0], &a8_1[i], 5);    /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[0, 8] overlaps between 2 and 5 bytes at offset \\\[0, 3\\\]" } */
+  T (&a8_1[0], &a8_1[i], 6);    /* { dg-warning "accessing 6 bytes at offsets 0 and \\\[0, 8] overlaps between 4 and 6 bytes at offset \\\[0, 2\\\]" } */
+  T (&a8_1[0], &a8_1[i], 7);    /* { dg-warning "accessing 7 bytes at offsets 0 and \\\[0, 8] overlaps between 6 and 7 bytes at offset \\\[0, 1\\\]" } */
+  T (&a8_1[0], &a8_1[i], 8);    /* { dg-warning "accessing 8 bytes at offsets 0 and \\\[0, 8] overlaps 8 bytes at offset 0" } */
+  T (&a8_1[0], &a8_1[i], 9);    /* { dg-warning "accessing 9 bytes at offsets 0 and \\\[0, 8] overlaps 9 bytes at offset 0" } */
+
+
+  /* Variable destination and source indices.  */
+  T (&a8_1[i], &a8_1[j], 1);
+  T (&a8_1[i], &a8_1[j], 2);
+  T (&a8_1[i], &a8_1[j], 3);
+  T (&a8_1[i], &a8_1[j], 4);
+
+  T (&a8_1[i], &a8_1[j], 5);    /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 2 and 5 bytes at offset \\\[0, 3\\\]" } */
+  T (&a8_1[i], &a8_1[j], 6);    /* { dg-warning "accessing 6 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 4 and 6 bytes at offset \\\[0, 2\\\]" } */
+  T (&a8_1[i], &a8_1[j], 7);    /* { dg-warning "accessing 7 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 6 and 7 bytes at offset \\\[0, 1\\\]" } */
+  T (&a8_1[i], &a8_1[j], 8);    /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps 8 bytes at offset 0" } */
+
+  /* The following is diagnosed by -Warray-bounds when it's enabled
+     rather than by -Wrestrict.  */
+  T (&a8_1[i], &a8_1[j], 9);    /* { dg-warning "accessing 9 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps 9 bytes at offset 0" } */
+}
+
+struct S4 { char a4[4]; } a2_4[2];
+
+void test_2_dim (int i, int j)
+{
+  T (&a2_4[i], &a2_4[0], 1);
+  T (&a2_4[i], &a2_4[0], 4);
+
+  T (&a2_4[i], &a2_4[0], 5);    /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and 0 overlaps between 2 and 5 bytes at offset \\\[0, 3]" } */
+  T (&a2_4[i], &a2_4[0], 6);    /* { dg-warning "accessing 6 bytes at offsets \\\[0, 8] and 0 overlaps between 4 and 6 bytes at offset \\\[0, 2]" } */
+  T (&a2_4[i], &a2_4[0], 7);    /* { dg-warning "accessing 7 bytes at offsets \\\[0, 8] and 0 overlaps between 6 and 7 bytes at offset \\\[0, 1]" } */
+  T (&a2_4[i], &a2_4[0], 8);    /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and 0 overlaps 8 bytes at offset 0" } */
+
+  T (a2_4[i].a4, a2_4[0].a4, 1);
+  T (a2_4[i].a4, a2_4[0].a4, 4);
+
+  T (a2_4[i].a4, a2_4[0].a4, 5);   /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and 0 overlaps between 2 and 5 bytes at offset \\\[0, 3]" } */
+  T (a2_4[i].a4, a2_4[0].a4, 8);   /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and 0 overlaps 8 bytes at offset 0" } */
+
+  T (a2_4[i].a4, a2_4[j].a4, 1);
+  T (a2_4[i].a4, a2_4[j].a4, 4);
+
+  /* The destination and source offsets printed below ignore the size
+     of the copy and only indicate the values that are valid for each
+     of the destination and source arguments on its own, without
+     considering the size of the overlapping access.  */
+  T (a2_4[i].a4, a2_4[j].a4, 5);   /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 2 and 5 bytes at offset \\\[0, 3]" } */
+  T (a2_4[i].a4, a2_4[j].a4, 8);   /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps 8 bytes at offset 0" } */
+
+  /* Same as above but referencing the first elements of each array.  */
+  T (&a2_4[i].a4[0], &a2_4[j].a4[0], 1);
+  T (&a2_4[i].a4[0], &a2_4[j].a4[0], 4);
+
+  T (&a2_4[i].a4[0], &a2_4[j].a4[0], 5);   /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 2 and 5 bytes at offset \\\[0, 3]" } */
+  T (&a2_4[i].a4[0], &a2_4[j].a4[0], 8);   /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps 8 bytes at offset 0" } */
+
+  T (&a2_4[i].a4[0], &a2_4[j].a4[1], 3);
+  T (&a2_4[i].a4[0], &a2_4[j].a4[2], 2);
+  T (&a2_4[i].a4[0], &a2_4[j].a4[3], 1);
+}
+
+struct { int i; } a2[2][8];
+
+void test_single_2_dim_major (int i)
+{
+  memcpy (&a2[i], &a2[0], sizeof *a2);   /* { dg-bogus "\\\[-Wrestrict]" } */
+}
+
+void test_single_2_dim_minor (int i)
+{
+  memcpy (&a2[i][0], &a2[0][0], sizeof a2[0][0]);   /* { dg-bogus "\\\[-Wrestrict]" } */
+}
+
+void test_single_2_dim_major_minor (int i, int j)
+{
+  memcpy (&a2[i][j], &a2[0][0], sizeof a2[0][0]);   /* { dg-bogus "\\\[-Wrestrict]" } */
+}
diff --git a/gcc/testsuite/gcc.dg/Wrestrict-9.c b/gcc/testsuite/gcc.dg/Wrestrict-9.c
new file mode 100644
index 0000000..c518b1b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wrestrict-9.c
@@ -0,0 +1,305 @@
+/* PR tree-optimization/84095 - false-positive -Wrestrict warnings for
+   strcpy within array
+   { dg-do compile }
+   { dg-options "-O2 -Wrestrict -ftrack-macro-expansion=0" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern void* memcpy (void* restrict, const void* restrict, size_t);
+extern char* strcpy (char* restrict, const char* restrict);
+
+#define T(d, s)   strcpy (d, s)
+
+struct MemArrays {
+  char *p;
+  char a2[3][9];
+  char a3[3][4][9];
+} a[2];
+
+struct NestedMemArrays {
+  struct MemArrays ma;
+  struct MemArrays ma1[2];
+} nma[2];
+
+/* Use a variable as the source of a copy to verify that VAR_DECL
+   is handled correctly when it's the source of GIMPLE assignment.  */
+const char *str = "1234567";
+
+void test_obj_2_dim_const (void)
+{
+  const char *s = strcpy (a[0].a2[0], "1234567");
+
+  T (a[0].a2[1], s);
+  T (a[0].a2[2], s);
+
+  T (a[0].a2[0] + 1, s);      /* { dg-warning "accessing 8 bytes at offsets 1 and 0 overlaps 7 bytes at offset 1" } */
+  T (a[0].a2[1] + 2, s);
+  T (a[0].a2[2] + 3, s);
+
+  T (a[1].a2[0], s);
+  T (a[1].a2[1], s);
+  T (a[1].a2[2], s);
+
+  T (a[1].a2[0] + 1, s);
+  T (a[1].a2[1] + 2, s);
+  T (a[1].a2[2] + 3, s);
+}
+
+void test_obj_nested_2_dim_const (void)
+{
+  const char *s = strcpy (nma[0].ma.a2[0], str);
+
+  T (nma[0].ma.a2[1], s);
+  T (nma[0].ma.a2[2], s);
+
+  T (nma[0].ma.a2[0] + 1, s);      /* { dg-warning "accessing 8 bytes at offsets 1 and 0 overlaps 7 bytes at offset 1" "bug " { xfail *-*-* } } */
+  T (nma[0].ma.a2[1] + 2, s);
+  T (nma[0].ma.a2[2] + 3, s);
+
+  T (nma[1].ma.a2[1], s);
+  T (nma[1].ma.a2[2], s);
+
+  T (nma[1].ma.a2[0] + 1, s);
+  T (nma[1].ma.a2[1] + 2, s);
+  T (nma[1].ma.a2[2] + 3, s);
+
+
+  T (nma[0].ma1[0].a2[1], s);
+  T (nma[0].ma1[0].a2[2], s);
+
+  T (nma[0].ma1[0].a2[0] + 1, s);
+  T (nma[0].ma1[0].a2[1] + 2, s);
+  T (nma[0].ma1[0].a2[2] + 3, s);
+
+  T (nma[1].ma1[0].a2[1], s);
+  T (nma[1].ma1[0].a2[2], s);
+
+  T (nma[1].ma1[0].a2[0] + 1, s);
+  T (nma[1].ma1[0].a2[1] + 2, s);
+  T (nma[1].ma1[0].a2[2] + 3, s);
+}
+
+void test_obj_2_dim_var (int i, int j)
+{
+  const char *s = memcpy (a[0].a2[0], "1234567", 8);
+
+  T (a[i].a2[0], s);          /* { dg-bogus "\\\[-Wrestrict]" } */
+  T (a[i].a2[1], s);
+  T (a[i].a2[2], s);
+
+  T (a[i].a2[0] + 1, s);
+  T (a[i].a2[1] + 1, s);
+  T (a[i].a2[2] + 1, s);
+
+  T (a[0].a2[i], s);          /* { dg-bogus "\\\[-Wrestrict]" } */
+  T (a[1].a2[i], s);
+
+  T (a[i].a2[0] + j, s);
+  T (a[i].a2[1] + j, s);
+  T (a[i].a2[2] + j, s);
+
+  T (a[0].a2[i] + 1, s);
+  T (a[1].a2[i] + 1, s);
+
+  T (a[0].a2[i] + j, s);
+  T (a[1].a2[i] + j, s);
+
+  if (i < 0 || 1 < i)
+    i = 1;
+
+  T (a[i].a2[0], s);
+  T (a[i].a2[1], s);
+  T (a[i].a2[2], s);
+
+  T (a[i].a2[0] + 1, s);
+  T (a[i].a2[1] + 1, s);
+  T (a[i].a2[2] + 1, s);
+
+  T (a[0].a2[i], s);
+  T (a[1].a2[i], s);
+
+  T (a[i].a2[0] + j, s);
+  T (a[i].a2[1] + j, s);
+  T (a[i].a2[2] + j, s);
+
+  T (a[0].a2[i] + 1, s);
+  T (a[1].a2[i] + 1, s);
+
+  T (a[0].a2[i] + j, s);
+  T (a[1].a2[i] + j, s);
+}
+
+void test_obj_nested_2_dim_var (int i, int j)
+{
+  const char *s = strcpy (nma[0].ma.a2[0], "1234567");
+
+  T (nma[i].ma.a2[0], s);     /* { dg-bogus "\\\[-Wrestrict]" } */
+  T (nma[i].ma.a2[1], s);
+  T (nma[i].ma.a2[2], s);
+
+  T (nma[i].ma.a2[0] + 1, s);
+  T (nma[i].ma.a2[1] + 1, s);
+  T (nma[i].ma.a2[2] + 1, s);
+
+  T (nma[0].ma.a2[i], s);     /* { dg-bogus "\\\[-Wrestrict]" } */
+  T (nma[1].ma.a2[i], s);
+
+  T (nma[i].ma.a2[0] + j, s);
+  T (nma[i].ma.a2[1] + j, s);
+  T (nma[i].ma.a2[2] + j, s);
+
+  T (nma[0].ma.a2[i] + 1, s);
+  T (nma[1].ma.a2[i] + 1, s);
+
+  T (nma[0].ma.a2[i] + j, s);
+  T (nma[1].ma.a2[i] + j, s);
+}
+
+void test_ref_2_dim_const (struct MemArrays *p)
+{
+  strcpy (p[0].a2[0], "1234567");
+  const char *s = p[0].a2[0];
+
+  T (p[0].a2[1], s);
+  T (p[0].a2[2], s);
+
+  T (p[1].a2[0], s);
+  T (p[1].a2[1], s);
+  T (p[1].a2[2], s);
+}
+
+void test_ref_2_dim_var (struct MemArrays *p, int i, int j)
+{
+  strcpy (p[0].a2[0], "1234567");
+  const char *s = p[0].a2[0];
+
+  T (p[i].a2[0], s);          /* { dg-bogus "\\\[-Wrestrict]" } */
+  T (p[i].a2[1], s);
+  T (p[i].a2[2], s);
+
+  T (p[0].a2[i], s);
+  T (p[1].a2[i], s);
+
+  T (p[i].a2[0] + j, s);
+  T (p[i].a2[1] + j, s);
+  T (p[i].a2[2] + j, s);
+
+  T (p[0].a2[i] + j, s);
+  T (p[1].a2[i] + j, s);
+}
+
+void test_obj_3_dim_var (int i, int j)
+{
+  strcpy (a[0].a3[0][0], "1234567");
+  const char *s = a[0].a3[0][0];
+
+  T (a[0].a3[0][i], s);
+  T (a[0].a3[1][i], s);
+  T (a[0].a3[2][i], s);
+
+  T (a[1].a3[0][i], s);
+  T (a[1].a3[1][i], s);
+  T (a[1].a3[2][i], s);
+
+  T (a[0].a3[i][0], s);       /* { dg-bogus "\\\[-Wrestrict\]" } */
+  T (a[0].a3[i][1], s);
+  T (a[0].a3[i][2], s);
+
+  T (a[1].a3[i][0], s);
+  T (a[1].a3[i][1], s);
+  T (a[1].a3[i][2], s);
+
+  T (a[i].a3[0][0], s);       /* { dg-bogus "\\\[-Wrestrict\]" } */
+  T (a[i].a3[0][1], s);
+  T (a[i].a3[0][2], s);
+
+  T (a[i].a3[1][0], s);
+  T (a[i].a3[1][1], s);
+  T (a[i].a3[1][2], s);
+
+  T (a[i].a3[2][0], s);
+  T (a[i].a3[2][1], s);
+  T (a[i].a3[2][2], s);
+
+
+  T (a[0].a3[0][i] + 1, s);
+  T (a[0].a3[1][i] + 1, s);
+  T (a[0].a3[2][i] + 1, s);
+
+  T (a[1].a3[0][i] + 1, s);
+  T (a[1].a3[1][i] + 1, s);
+  T (a[1].a3[2][i] + 1, s);
+
+
+  T (a[0].a3[0][i] + j, s);
+  T (a[0].a3[1][i] + j, s);
+  T (a[0].a3[2][i] + j, s);
+
+  T (a[1].a3[0][i] + j, s);
+  T (a[1].a3[1][i] + j, s);
+  T (a[1].a3[2][i] + j, s);
+
+  T (a[0].a3[i][0] + j, s);
+  T (a[0].a3[i][1] + j, s);
+  T (a[0].a3[i][2] + j, s);
+
+  T (a[1].a3[i][0] + j, s);
+  T (a[1].a3[i][1] + j, s);
+  T (a[1].a3[i][2] + j, s);
+
+  T (a[i].a3[0][0] + j, s);
+  T (a[i].a3[0][1] + j, s);
+  T (a[i].a3[0][2] + j, s);
+
+  T (a[i].a3[1][0] + j, s);
+  T (a[i].a3[1][1] + j, s);
+  T (a[i].a3[1][2] + j, s);
+
+  T (a[i].a3[2][0] + j, s);
+  T (a[i].a3[2][1] + j, s);
+  T (a[i].a3[2][2] + j, s);
+}
+
+void test_obj_3_dim_const (struct MemArrays *p)
+{
+  strcpy (p[0].a3[0][0], "1234567");
+  const char *s = p[0].a3[0][0];
+
+  T (p[0].a3[0][1], s);
+  T (p[0].a3[0][2], s);
+  T (p[0].a3[0][3], s);
+
+  T (p[0].a3[0][1] + 1, s);
+  T (p[0].a3[0][2] + 1, s);
+  T (p[0].a3[0][3] + 1, s);
+
+  T (p[0].a3[1][0], s);
+  T (p[0].a3[1][1], s);
+  T (p[0].a3[1][2], s);
+  T (p[0].a3[1][3], s);
+
+  T (p[0].a3[1][0] + 1, s);
+  T (p[0].a3[1][1] + 1, s);
+  T (p[0].a3[1][2] + 1, s);
+  T (p[0].a3[1][3] + 1, s);
+
+  T (p[0].a3[2][0], s);
+  T (p[0].a3[2][1], s);
+  T (p[0].a3[2][2], s);
+  T (p[0].a3[2][3], s);
+
+  T (p[1].a3[0][0], s);
+  T (p[1].a3[0][1], s);
+  T (p[1].a3[0][2], s);
+  T (p[1].a3[0][3], s);
+
+  T (p[1].a3[1][0], s);
+  T (p[1].a3[1][1], s);
+  T (p[1].a3[1][2], s);
+  T (p[1].a3[1][3], s);
+
+  T (p[1].a3[2][0], s);
+  T (p[1].a3[2][1], s);
+  T (p[1].a3[2][2], s);
+  T (p[1].a3[2][3], s);
+}
diff --git a/gcc/testsuite/gcc.dg/pr84095.c b/gcc/testsuite/gcc.dg/pr84095.c
new file mode 100644
index 0000000..af2bc0e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr84095.c
@@ -0,0 +1,14 @@
+/* PR tree-optimization/84095 - false-positive -Wrestrict warnings for
+   memcpy within array
+   { dg-do compile }
+   { dg-options "-O2 -Wrestrict" } */
+
+struct { int i; } a[8];
+
+void f (void)
+{
+  int i;
+
+  for (i = 1; i < 8; i++)
+    __builtin_memcpy (&a[i], &a[0], sizeof(a[0]));   /* { dg-bogus "\\\[-Wrestrict]" } */
+}

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] correct -Wrestrict handling of arrays of arrays (PR 84095)
  2018-02-01 23:45 ` Martin Sebor
@ 2018-02-09  2:46   ` Martin Sebor
  2018-02-14  6:14   ` Jeff Law
  2018-02-23  3:17   ` Siddhesh Poyarekar
  2 siblings, 0 replies; 10+ messages in thread
From: Martin Sebor @ 2018-02-09  2:46 UTC (permalink / raw)
  To: Gcc Patch List, Jakub Jelinek

Ping: https://gcc.gnu.org/ml/gcc-patches/2018-02/msg00076.html

On 02/01/2018 04:45 PM, Martin Sebor wrote:
> The previous patch didn't resolve all the false positives
> in the Linux kernel.  The attached is an update that fixes
> the remaining one having to do with multidimensional array
> members:
>
>   struct S { char a[2][4]; };
>
>   void f (struct S *p, int i)
>   {
>     strcpy (p->a[0], "012");
>     strcpy (p->a[i] + 1, p->a[0]);   // false positive here
>   }
>
> In the process of fixing this I also made a couple of minor
> restructuring changes to the builtin_memref constructor to
> in order to make the code easier to follow: I broke it out
> into a couple of helper functions and called those.
>
> As with the first revision of the patch, this one is also
> meant to be applied on top of
>
>   https://gcc.gnu.org/ml/gcc-patches/2018-01/msg01488.html
>
> Sorry about the late churn.  Even though I tested the original
> implementation with the Linux kernel the bugs were only exposed
> non-default configurations that I didn't build.
>
> Jakub, you had concerns about the code in the constructor
> and about interpreting the offsets in the diagnostics.
> I tried to address those in the patch.  Please review
> the changes and let me know if you have any further comments.
>
> Thanks
> Martin
>
> On 01/30/2018 04:19 PM, Martin Sebor wrote:
>> Testing GCC 8 with recent Linux kernel sources has uncovered
>> a bug in the handling of arrays of arrays by the -Wrestrict
>> checker where it fails to take references to different array
>> elements into consideration, issuing false positives.
>>
>> The attached patch corrects this mistake.
>>
>> In addition, to make warnings involving excessive offset bounds
>> more meaningful (less confusing), I've made a cosmetic change
>> to constrain them to the bounds of the accessed object.  I've
>> done this in response to multiple comments indicating that
>> the warnings are hard to interpret.  This change is meant to
>> be applied on top of the patch for bug 83698 (submitted mainly
>> to improve the readability of the offsets):
>>
>>   https://gcc.gnu.org/ml/gcc-patches/2018-01/msg01488.html
>>
>> Martin
>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] correct -Wrestrict handling of arrays of arrays (PR 84095)
  2018-02-01 23:45 ` Martin Sebor
  2018-02-09  2:46   ` Martin Sebor
@ 2018-02-14  6:14   ` Jeff Law
  2018-02-15 17:48     ` Martin Sebor
  2018-02-23  3:17   ` Siddhesh Poyarekar
  2 siblings, 1 reply; 10+ messages in thread
From: Jeff Law @ 2018-02-14  6:14 UTC (permalink / raw)
  To: Martin Sebor, Gcc Patch List, Jakub Jelinek

On 02/01/2018 04:45 PM, Martin Sebor wrote:
> The previous patch didn't resolve all the false positives
> in the Linux kernel.  The attached is an update that fixes
> the remaining one having to do with multidimensional array
> members:
> 
>   struct S { char a[2][4]; };
> 
>   void f (struct S *p, int i)
>   {
>     strcpy (p->a[0], "012");
>     strcpy (p->a[i] + 1, p->a[0]);   // false positive here
>   }
> 
> In the process of fixing this I also made a couple of minor
> restructuring changes to the builtin_memref constructor to
> in order to make the code easier to follow: I broke it out
> into a couple of helper functions and called those.
> 
> As with the first revision of the patch, this one is also
> meant to be applied on top of
> 
>   https://gcc.gnu.org/ml/gcc-patches/2018-01/msg01488.html
> 
> Sorry about the late churn.  Even though I tested the original
> implementation with the Linux kernel the bugs were only exposed
> non-default configurations that I didn't build.
> 
> Jakub, you had concerns about the code in the constructor
> and about interpreting the offsets in the diagnostics.
> I tried to address those in the patch.  Please review
> the changes and let me know if you have any further comments.
> 
> Thanks
> Martin
> 
> On 01/30/2018 04:19 PM, Martin Sebor wrote:
>> Testing GCC 8 with recent Linux kernel sources has uncovered
>> a bug in the handling of arrays of arrays by the -Wrestrict
>> checker where it fails to take references to different array
>> elements into consideration, issuing false positives.
>>
>> The attached patch corrects this mistake.
>>
>> In addition, to make warnings involving excessive offset bounds
>> more meaningful (less confusing), I've made a cosmetic change
>> to constrain them to the bounds of the accessed object.  I've
>> done this in response to multiple comments indicating that
>> the warnings are hard to interpret.  This change is meant to
>> be applied on top of the patch for bug 83698 (submitted mainly
>> to improve the readability of the offsets):
>>
>>   https://gcc.gnu.org/ml/gcc-patches/2018-01/msg01488.html
>>
>> Martin
> 
> 
> gcc-84095.diff
> 
> 
> PR middle-end/84095 - false-positive -Wrestrict warnings for memcpy within array
> 
> gcc/ChangeLog:
> 
> 	PR middle-end/84095
> 	* gimple-ssa-warn-restrict.c (builtin_memref::extend_offset_range): New.
> 	(builtin_memref::set_base_and_offset): Same.  Handle inner references.
> 	(builtin_memref::builtin_memref): Factor out parts into
> 	set_base_and_offset and call it.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR middle-end/84095
> 	* c-c++-common/Warray-bounds-3.c: Adjust text of expected warnings.
> 	* c-c++-common/Wrestrict.c: Same.
> 	* gcc.dg/Wrestrict-6.c: Same.
> 	* gcc.dg/Warray-bounds-27.c: New test.
> 	* gcc.dg/Wrestrict-8.c: New test.
> 	* gcc.dg/Wrestrict-9.c: New test.
> 	* gcc.dg/pr84095.c: New test.
> 
> diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c
> index 528eb5b..367e05f 100644
> --- a/gcc/gimple-ssa-warn-restrict.c
> +++ b/gcc/gimple-ssa-warn-restrict.c

> +      else if (gimple_nop_p (stmt))
> +	expr = SSA_NAME_VAR (expr);
> +      else
> +	{
> +	  base = expr;
> +	  return;
>  	}
This looks odd.  Can you explain what you're trying to do here?

I'm not offhand why you'd ever want to extract SSA_NAME_VAR.  In general
it's primary use is for dumps and debugging info.  I won't quite go so
far as to say using it for anything else is wrong, but it's certainly
something you ought to explain.


The rest looks fairly reasonable.  It's a bit hard to follow, but I
don't think we should do another round of refactoring at this stage.

jeff

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] correct -Wrestrict handling of arrays of arrays (PR 84095)
  2018-02-14  6:14   ` Jeff Law
@ 2018-02-15 17:48     ` Martin Sebor
  2018-02-16 23:39       ` Jeff Law
  0 siblings, 1 reply; 10+ messages in thread
From: Martin Sebor @ 2018-02-15 17:48 UTC (permalink / raw)
  To: Jeff Law, Gcc Patch List, Jakub Jelinek

On 02/13/2018 11:14 PM, Jeff Law wrote:
> On 02/01/2018 04:45 PM, Martin Sebor wrote:
>> The previous patch didn't resolve all the false positives
>> in the Linux kernel.  The attached is an update that fixes
>> the remaining one having to do with multidimensional array
>> members:
>>
>>   struct S { char a[2][4]; };
>>
>>   void f (struct S *p, int i)
>>   {
>>     strcpy (p->a[0], "012");
>>     strcpy (p->a[i] + 1, p->a[0]);   // false positive here
>>   }
>>
>> In the process of fixing this I also made a couple of minor
>> restructuring changes to the builtin_memref constructor to
>> in order to make the code easier to follow: I broke it out
>> into a couple of helper functions and called those.
>>
>> As with the first revision of the patch, this one is also
>> meant to be applied on top of
>>
>>   https://gcc.gnu.org/ml/gcc-patches/2018-01/msg01488.html
>>
>> Sorry about the late churn.  Even though I tested the original
>> implementation with the Linux kernel the bugs were only exposed
>> non-default configurations that I didn't build.
>>
>> Jakub, you had concerns about the code in the constructor
>> and about interpreting the offsets in the diagnostics.
>> I tried to address those in the patch.  Please review
>> the changes and let me know if you have any further comments.
>>
>> Thanks
>> Martin
>>
>> On 01/30/2018 04:19 PM, Martin Sebor wrote:
>>> Testing GCC 8 with recent Linux kernel sources has uncovered
>>> a bug in the handling of arrays of arrays by the -Wrestrict
>>> checker where it fails to take references to different array
>>> elements into consideration, issuing false positives.
>>>
>>> The attached patch corrects this mistake.
>>>
>>> In addition, to make warnings involving excessive offset bounds
>>> more meaningful (less confusing), I've made a cosmetic change
>>> to constrain them to the bounds of the accessed object.  I've
>>> done this in response to multiple comments indicating that
>>> the warnings are hard to interpret.  This change is meant to
>>> be applied on top of the patch for bug 83698 (submitted mainly
>>> to improve the readability of the offsets):
>>>
>>>   https://gcc.gnu.org/ml/gcc-patches/2018-01/msg01488.html
>>>
>>> Martin
>>
>>
>> gcc-84095.diff
>>
>>
>> PR middle-end/84095 - false-positive -Wrestrict warnings for memcpy within array
>>
>> gcc/ChangeLog:
>>
>> 	PR middle-end/84095
>> 	* gimple-ssa-warn-restrict.c (builtin_memref::extend_offset_range): New.
>> 	(builtin_memref::set_base_and_offset): Same.  Handle inner references.
>> 	(builtin_memref::builtin_memref): Factor out parts into
>> 	set_base_and_offset and call it.
>>
>> gcc/testsuite/ChangeLog:
>>
>> 	PR middle-end/84095
>> 	* c-c++-common/Warray-bounds-3.c: Adjust text of expected warnings.
>> 	* c-c++-common/Wrestrict.c: Same.
>> 	* gcc.dg/Wrestrict-6.c: Same.
>> 	* gcc.dg/Warray-bounds-27.c: New test.
>> 	* gcc.dg/Wrestrict-8.c: New test.
>> 	* gcc.dg/Wrestrict-9.c: New test.
>> 	* gcc.dg/pr84095.c: New test.
>>
>> diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c
>> index 528eb5b..367e05f 100644
>> --- a/gcc/gimple-ssa-warn-restrict.c
>> +++ b/gcc/gimple-ssa-warn-restrict.c
>
>> +      else if (gimple_nop_p (stmt))
>> +	expr = SSA_NAME_VAR (expr);
>> +      else
>> +	{
>> +	  base = expr;
>> +	  return;
>>  	}
> This looks odd.  Can you explain what you're trying to do here?
>
> I'm not offhand why you'd ever want to extract SSA_NAME_VAR.  In general
> it's primary use is for dumps and debugging info.  I won't quite go so
> far as to say using it for anything else is wrong, but it's certainly
> something you ought to explain.

It appears to be dead code.  Nothing in the GCC test suite hits
this code.  It's most likely a vestige of an approach I tried
that didn't work and that I ended up doing differently and forgot
to remove.  I'll remove it before committing.

> The rest looks fairly reasonable.  It's a bit hard to follow, but I
> don't think we should do another round of refactoring at this stage.

Is the patch good to commit then with the unused code above
removed?

Martin

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] correct -Wrestrict handling of arrays of arrays (PR 84095)
  2018-02-15 17:48     ` Martin Sebor
@ 2018-02-16 23:39       ` Jeff Law
  0 siblings, 0 replies; 10+ messages in thread
From: Jeff Law @ 2018-02-16 23:39 UTC (permalink / raw)
  To: Martin Sebor, Gcc Patch List, Jakub Jelinek

On 02/15/2018 10:47 AM, Martin Sebor wrote:
> On 02/13/2018 11:14 PM, Jeff Law wrote:
>> On 02/01/2018 04:45 PM, Martin Sebor wrote:
>>> The previous patch didn't resolve all the false positives
>>> in the Linux kernel.  The attached is an update that fixes
>>> the remaining one having to do with multidimensional array
>>> members:
>>>
>>>   struct S { char a[2][4]; };
>>>
>>>   void f (struct S *p, int i)
>>>   {
>>>     strcpy (p->a[0], "012");
>>>     strcpy (p->a[i] + 1, p->a[0]);   // false positive here
>>>   }
>>>
>>> In the process of fixing this I also made a couple of minor
>>> restructuring changes to the builtin_memref constructor to
>>> in order to make the code easier to follow: I broke it out
>>> into a couple of helper functions and called those.
>>>
>>> As with the first revision of the patch, this one is also
>>> meant to be applied on top of
>>>
>>>   https://gcc.gnu.org/ml/gcc-patches/2018-01/msg01488.html
>>>
>>> Sorry about the late churn.  Even though I tested the original
>>> implementation with the Linux kernel the bugs were only exposed
>>> non-default configurations that I didn't build.
>>>
>>> Jakub, you had concerns about the code in the constructor
>>> and about interpreting the offsets in the diagnostics.
>>> I tried to address those in the patch.  Please review
>>> the changes and let me know if you have any further comments.
>>>
>>> Thanks
>>> Martin
>>>
>>> On 01/30/2018 04:19 PM, Martin Sebor wrote:
>>>> Testing GCC 8 with recent Linux kernel sources has uncovered
>>>> a bug in the handling of arrays of arrays by the -Wrestrict
>>>> checker where it fails to take references to different array
>>>> elements into consideration, issuing false positives.
>>>>
>>>> The attached patch corrects this mistake.
>>>>
>>>> In addition, to make warnings involving excessive offset bounds
>>>> more meaningful (less confusing), I've made a cosmetic change
>>>> to constrain them to the bounds of the accessed object.  I've
>>>> done this in response to multiple comments indicating that
>>>> the warnings are hard to interpret.  This change is meant to
>>>> be applied on top of the patch for bug 83698 (submitted mainly
>>>> to improve the readability of the offsets):
>>>>
>>>>   https://gcc.gnu.org/ml/gcc-patches/2018-01/msg01488.html
>>>>
>>>> Martin
>>>
>>>
>>> gcc-84095.diff
>>>
>>>
>>> PR middle-end/84095 - false-positive -Wrestrict warnings for memcpy
>>> within array
>>>
>>> gcc/ChangeLog:
>>>
>>>     PR middle-end/84095
>>>     * gimple-ssa-warn-restrict.c
>>> (builtin_memref::extend_offset_range): New.
>>>     (builtin_memref::set_base_and_offset): Same.  Handle inner
>>> references.
>>>     (builtin_memref::builtin_memref): Factor out parts into
>>>     set_base_and_offset and call it.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>>     PR middle-end/84095
>>>     * c-c++-common/Warray-bounds-3.c: Adjust text of expected warnings.
>>>     * c-c++-common/Wrestrict.c: Same.
>>>     * gcc.dg/Wrestrict-6.c: Same.
>>>     * gcc.dg/Warray-bounds-27.c: New test.
>>>     * gcc.dg/Wrestrict-8.c: New test.
>>>     * gcc.dg/Wrestrict-9.c: New test.
>>>     * gcc.dg/pr84095.c: New test.
>>>
>>> diff --git a/gcc/gimple-ssa-warn-restrict.c
>>> b/gcc/gimple-ssa-warn-restrict.c
>>> index 528eb5b..367e05f 100644
>>> --- a/gcc/gimple-ssa-warn-restrict.c
>>> +++ b/gcc/gimple-ssa-warn-restrict.c
>>
>>> +      else if (gimple_nop_p (stmt))
>>> +    expr = SSA_NAME_VAR (expr);
>>> +      else
>>> +    {
>>> +      base = expr;
>>> +      return;
>>>      }
>> This looks odd.  Can you explain what you're trying to do here?
>>
>> I'm not offhand why you'd ever want to extract SSA_NAME_VAR.  In general
>> it's primary use is for dumps and debugging info.  I won't quite go so
>> far as to say using it for anything else is wrong, but it's certainly
>> something you ought to explain.
> 
> It appears to be dead code.  Nothing in the GCC test suite hits
> this code.  It's most likely a vestige of an approach I tried
> that didn't work and that I ended up doing differently and forgot
> to remove.  I'll remove it before committing.
> 
>> The rest looks fairly reasonable.  It's a bit hard to follow, but I
>> don't think we should do another round of refactoring at this stage.
> 
> Is the patch good to commit then with the unused code above
> removed?
Yes.  Again, sorry for the delays.

jeff

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] correct -Wrestrict handling of arrays of arrays (PR 84095)
  2018-02-01 23:45 ` Martin Sebor
  2018-02-09  2:46   ` Martin Sebor
  2018-02-14  6:14   ` Jeff Law
@ 2018-02-23  3:17   ` Siddhesh Poyarekar
  2018-02-23 15:52     ` Martin Sebor
  2 siblings, 1 reply; 10+ messages in thread
From: Siddhesh Poyarekar @ 2018-02-23  3:17 UTC (permalink / raw)
  To: Martin Sebor, Gcc Patch List, Jakub Jelinek

On Friday 02 February 2018 05:15 AM, Martin Sebor wrote:
> PR middle-end/84095 - false-positive -Wrestrict warnings for memcpy within array
> 
> gcc/ChangeLog:
> 
> 	PR middle-end/84095
> 	* gimple-ssa-warn-restrict.c (builtin_memref::extend_offset_range): New.
> 	(builtin_memref::set_base_and_offset): Same.  Handle inner references.
> 	(builtin_memref::builtin_memref): Factor out parts into
> 	set_base_and_offset and call it.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR middle-end/84095
> 	* c-c++-common/Warray-bounds-3.c: Adjust text of expected warnings.
> 	* c-c++-common/Wrestrict.c: Same.
> 	* gcc.dg/Wrestrict-6.c: Same.
> 	* gcc.dg/Warray-bounds-27.c: New test.
> 	* gcc.dg/Wrestrict-8.c: New test.
> 	* gcc.dg/Wrestrict-9.c: New test.
> 	* gcc.dg/pr84095.c: New test.

This is causing failures in Warray-bounds-2.c in the testsuite:

FAIL: c-c++-common/Warray-bounds-2.c  -Wc++-compat  memcpy (test for
warnings, line 67)
FAIL: c-c++-common/Warray-bounds-2.c  -Wc++-compat   (test for warnings,
line 72)
FAIL: c-c++-common/Warray-bounds-2.c  -Wc++-compat  strncpy (test for
warnings, line 178)
FAIL: c-c++-common/Warray-bounds-2.c  -Wc++-compat   (test for warnings,
line 183)
FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++98 memcpy (test for
warnings, line 67)
FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++98  (test for warnings,
line 72)
FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++98 strncpy (test for
warnings, line 178)
FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++98  (test for warnings,
line 183)
FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++11 memcpy (test for
warnings, line 67)
FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++11  (test for warnings,
line 72)
FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++11 strncpy (test for
warnings, line 178)
FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++11  (test for warnings,
line 183)
FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++14 memcpy (test for
warnings, line 67)
FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++14  (test for warnings,
line 72)
FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++14 strncpy (test for
warnings, line 178)
FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++14  (test for warnings,
line 183)

Siddhesh

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] correct -Wrestrict handling of arrays of arrays (PR 84095)
  2018-02-23  3:17   ` Siddhesh Poyarekar
@ 2018-02-23 15:52     ` Martin Sebor
  2018-02-23 16:19       ` Siddhesh Poyarekar
  2018-02-23 16:49       ` Jakub Jelinek
  0 siblings, 2 replies; 10+ messages in thread
From: Martin Sebor @ 2018-02-23 15:52 UTC (permalink / raw)
  To: Siddhesh Poyarekar, Gcc Patch List, Jakub Jelinek

On 02/22/2018 08:17 PM, Siddhesh Poyarekar wrote:
> On Friday 02 February 2018 05:15 AM, Martin Sebor wrote:
>> PR middle-end/84095 - false-positive -Wrestrict warnings for memcpy within array
>>
>> gcc/ChangeLog:
>>
>> 	PR middle-end/84095
>> 	* gimple-ssa-warn-restrict.c (builtin_memref::extend_offset_range): New.
>> 	(builtin_memref::set_base_and_offset): Same.  Handle inner references.
>> 	(builtin_memref::builtin_memref): Factor out parts into
>> 	set_base_and_offset and call it.
>>
>> gcc/testsuite/ChangeLog:
>>
>> 	PR middle-end/84095
>> 	* c-c++-common/Warray-bounds-3.c: Adjust text of expected warnings.
>> 	* c-c++-common/Wrestrict.c: Same.
>> 	* gcc.dg/Wrestrict-6.c: Same.
>> 	* gcc.dg/Warray-bounds-27.c: New test.
>> 	* gcc.dg/Wrestrict-8.c: New test.
>> 	* gcc.dg/Wrestrict-9.c: New test.
>> 	* gcc.dg/pr84095.c: New test.
>
> This is causing failures in Warray-bounds-2.c in the testsuite:
>
> FAIL: c-c++-common/Warray-bounds-2.c  -Wc++-compat  memcpy (test for
> warnings, line 67)

I see no failures in this test in any of the recently reported
results on any targets except those below:

   https://gcc.gnu.org/ml/gcc-testresults/2018-02/msg01530.html
   https://gcc.gnu.org/ml/gcc-testresults/2018-02/msg01514.html

There are a large number of failures in these reports in many
tests that were reported previously (before r257910), suggesting
something else is wrong.  They all seem to use -fpic.

If you referring to some other report or your own result please
post a link or say what target/configuration, etc..

Martin


> FAIL: c-c++-common/Warray-bounds-2.c  -Wc++-compat   (test for warnings,
> line 72)
> FAIL: c-c++-common/Warray-bounds-2.c  -Wc++-compat  strncpy (test for
> warnings, line 178)
> FAIL: c-c++-common/Warray-bounds-2.c  -Wc++-compat   (test for warnings,
> line 183)
> FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++98 memcpy (test for
> warnings, line 67)
> FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++98  (test for warnings,
> line 72)
> FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++98 strncpy (test for
> warnings, line 178)
> FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++98  (test for warnings,
> line 183)
> FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++11 memcpy (test for
> warnings, line 67)
> FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++11  (test for warnings,
> line 72)
> FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++11 strncpy (test for
> warnings, line 178)
> FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++11  (test for warnings,
> line 183)
> FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++14 memcpy (test for
> warnings, line 67)
> FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++14  (test for warnings,
> line 72)
> FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++14 strncpy (test for
> warnings, line 178)
> FAIL: c-c++-common/Warray-bounds-2.c  -std=gnu++14  (test for warnings,
> line 183)
>
> Siddhesh
>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] correct -Wrestrict handling of arrays of arrays (PR 84095)
  2018-02-23 15:52     ` Martin Sebor
@ 2018-02-23 16:19       ` Siddhesh Poyarekar
  2018-02-23 16:49       ` Jakub Jelinek
  1 sibling, 0 replies; 10+ messages in thread
From: Siddhesh Poyarekar @ 2018-02-23 16:19 UTC (permalink / raw)
  To: Martin Sebor, Gcc Patch List, Jakub Jelinek

On Friday 23 February 2018 09:22 PM, Martin Sebor wrote:
> I see no failures in this test in any of the recently reported
> results on any targets except those below:
> 
>   https://gcc.gnu.org/ml/gcc-testresults/2018-02/msg01530.html
>   https://gcc.gnu.org/ml/gcc-testresults/2018-02/msg01514.html
> 
> There are a large number of failures in these reports in many
> tests that were reported previously (before r257910), suggesting
> something else is wrong.  They all seem to use -fpic.
> 
> If you referring to some other report or your own result please
> post a link or say what target/configuration, etc..

This was on my x86_64 box (Xeon(R) CPU E5-2623) and a standard
x86_64-pc-linux-gnu native build.  It was after an incremental build
though, so I'll schedule a fresh one next week to confirm if you think
that shouldn't happen.

Siddhesh

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] correct -Wrestrict handling of arrays of arrays (PR 84095)
  2018-02-23 15:52     ` Martin Sebor
  2018-02-23 16:19       ` Siddhesh Poyarekar
@ 2018-02-23 16:49       ` Jakub Jelinek
  1 sibling, 0 replies; 10+ messages in thread
From: Jakub Jelinek @ 2018-02-23 16:49 UTC (permalink / raw)
  To: Jeff Law, Rainer Orth, Mike Stump, Martin Sebor
  Cc: Siddhesh Poyarekar, Gcc Patch List

On Fri, Feb 23, 2018 at 08:52:19AM -0700, Martin Sebor wrote:
> There are a large number of failures in these reports in many
> tests that were reported previously (before r257910), suggesting
> something else is wrong.  They all seem to use -fpic.
> 
> If you referring to some other report or your own result please
> post a link or say what target/configuration, etc..

The testcase clearly relies on inlining all the wrap_* functions,
but as they are void wrap_* with -fpic/-fPIC obviously they can't be
inlined at -O2, the executable or some other shared library might define
some other implementation of those and interpose it.
Some targets default to -fpic even.

The following patch just adds static inline to them, so that it works
even with -fpic, as tested with:
make check-gcc check-g++ RUNTESTFLAGS='--target_board=unix\{,-fpic,-fpie\} dg.exp=Warray-bounds*'

Ok for trunk?

2018-02-23  Jakub Jelinek  <jakub@redhat.com>

	* c-c++-common/Warray-bounds-2.c (wrap_memcpy_src_xsize,
	wrap_memcpy_src_diff_max, wrap_memcpy_dst_xsize,
	wrap_memcpy_dst_diff_max, wrap_strcat_src_xsize,
	wrap_strcat_dst_xsize, wrap_strcpy_src_xsize,
	wrap_strcpy_dst_xsize, wrap_strncpy_src_xsize,
	wrap_strncpy_src_diff_max, wrap_strncpy_dst_xsize,
	wrap_strncpy_dst_diff_max, wrap_strncpy_dstarray_diff_neg): Add
	static inline.

--- gcc/testsuite/c-c++-common/Warray-bounds-2.c.jj	2017-12-18 14:57:15.601127538 +0100
+++ gcc/testsuite/c-c++-common/Warray-bounds-2.c	2018-02-23 17:12:47.114113757 +0100
@@ -1,4 +1,4 @@
-/* Test to exercise that -Warray-bounds warnings for memory and sring
+/* Test to exercise that -Warray-bounds warnings for memory and string
    functions are issued even when they are declared in system headers
    (i.e., not just when they are explicitly declared in the source
    file.)
@@ -24,7 +24,7 @@ struct __attribute__ ((packed)) Array
 
 /* Exercise memcpy out-of-bounds offsets with an array of known size.  */
 
-void wrap_memcpy_src_xsize (char *d, const char *s, ptrdiff_t i, size_t n)
+static inline void wrap_memcpy_src_xsize (char *d, const char *s, ptrdiff_t i, size_t n)
 {
   memcpy (d, s + i, n);   /* { dg-warning "offset 46 is out of the bounds \\\[0, 45] of object .ar. with type .(struct )?Array." "memcpy" } */
 }
@@ -39,7 +39,7 @@ void call_memcpy_src_xsize (char *d, siz
 
 /* Exercise memcpy out-of-bounds offsets with an array of unknown size.  */
 
-void wrap_memcpy_src_diff_max (char *d, const char *s, ptrdiff_t i, size_t n)
+static inline void wrap_memcpy_src_diff_max (char *d, const char *s, ptrdiff_t i, size_t n)
 {
   memcpy (d, s + i, n);   /* { dg-warning "pointer overflow between offset \[0-9\]+ and size 3" "memcpy" } */
 }
@@ -49,7 +49,7 @@ void call_memcpy_src_diff_max (char *d,
   wrap_memcpy_src_diff_max (d, s, MAX, 3);
 }
 
-void wrap_memcpy_dst_xsize (char *d, const char *s, ptrdiff_t i, size_t n)
+static inline void wrap_memcpy_dst_xsize (char *d, const char *s, ptrdiff_t i, size_t n)
 {
   memcpy (d + i, s, n);   /* { dg-warning "offset 47 is out of the bounds \\\[0, 45] of object .ar1. with type .(struct )?Array." "memcpy" } */
 }
@@ -62,7 +62,7 @@ void call_memcpy_dst_xsize (const char *
   sink (&ar1);
 }
 
-void wrap_memcpy_dst_diff_max (char *d, const char *s, ptrdiff_t i, size_t n)
+static inline void wrap_memcpy_dst_diff_max (char *d, const char *s, ptrdiff_t i, size_t n)
 {
   memcpy (d + i, s, n);   /* { dg-warning "offset -?\[0-9\]+ is out of the bounds \\\[0, 45] of object .ar2. with type .(struct )?Array." "memcpy" } */
 }
@@ -76,7 +76,7 @@ void call_memcpy_dst_diff_max (const cha
 }
 
 
-void wrap_strcat_src_xsize (char *d, const char *s, ptrdiff_t i)
+static inline void wrap_strcat_src_xsize (char *d, const char *s, ptrdiff_t i)
 {
   strcat (d, s + i);   /* { dg-warning "offset 46 is out of the bounds \\\[0, 45] of object .ar3. with type .(struct )?Array." "strcat" } */
 }
@@ -89,7 +89,7 @@ void call_strcat_src_xsize (char *d)
   sink (&ar3);
 }
 
-void wrap_strcat_dst_xsize (char *d, const char *s, ptrdiff_t i)
+static inline void wrap_strcat_dst_xsize (char *d, const char *s, ptrdiff_t i)
 {
   strcat (d + i, s);   /* { dg-warning "offset 47 is out of the bounds \\\[0, 45] of object .ar4. with type .(struct )?Array." "strcat" } */
 }
@@ -103,7 +103,7 @@ void call_strcat_dst_xsize (const char *
 }
 
 
-void wrap_strcpy_src_xsize (char *d, const char *s, ptrdiff_t i)
+static inline void wrap_strcpy_src_xsize (char *d, const char *s, ptrdiff_t i)
 {
   strcpy (d, s + i);   /* { dg-warning "offset 48 is out of the bounds \\\[0, 45] of object .ar5. with type .(struct )?Array." "strcpy" } */
 }
@@ -116,7 +116,7 @@ void call_strcpy_src_xsize (char *d)
   sink (&ar5);
 }
 
-void wrap_strcpy_dst_xsize (char *d, const char *s, ptrdiff_t i)
+static inline void wrap_strcpy_dst_xsize (char *d, const char *s, ptrdiff_t i)
 {
   strcpy (d + i, s);   /* { dg-warning "offset 49 is out of the bounds \\\[0, 45] of object .ar6. with type .(struct )?Array." "strcpy" } */
 }
@@ -132,7 +132,7 @@ void call_strcpy_dst_xsize (const char *
 
 /* Exercise strncpy out-of-bounds offsets with an array of known size.  */
 
-void wrap_strncpy_src_xsize (char *d, const char *s, ptrdiff_t i, size_t n)
+static inline void wrap_strncpy_src_xsize (char *d, const char *s, ptrdiff_t i, size_t n)
 {
   strncpy (d, s + i, n);   /* { dg-warning "offset 46 is out of the bounds \\\[0, 45] of object .ar7. with type '(struct )?Array." "strncpy" } */
 }
@@ -147,7 +147,7 @@ void call_strncpy_src_xsize (char *d, si
 
 /* Exercise strncpy out-of-bounds offsets with an array of unknown size.  */
 
-void wrap_strncpy_src_diff_max (char *d, const char *s, ptrdiff_t i, size_t n)
+static inline void wrap_strncpy_src_diff_max (char *d, const char *s, ptrdiff_t i, size_t n)
 {
   /* Unlike in the similar call to memcpy(), there is no pointer
      overflow here because the size N is not added to the source
@@ -160,7 +160,7 @@ void call_strncpy_src_diff_max (char *d,
   wrap_strncpy_src_diff_max (d, s, MAX, 3);
 }
 
-void wrap_strncpy_dst_xsize (char *d, const char *s, ptrdiff_t i, size_t n)
+static inline void wrap_strncpy_dst_xsize (char *d, const char *s, ptrdiff_t i, size_t n)
 {
   strncpy (d + i, s, n);   /* { dg-warning "offset 47 is out of the bounds \\\[0, 45] of object .ar8. with type .(struct )?Array." "strncpy" } */
 }
@@ -173,7 +173,7 @@ void call_strncpy_dst_xsize (const char
   sink (&ar8);
 }
 
-void wrap_strncpy_dst_diff_max (char *d, const char *s, ptrdiff_t i, size_t n)
+static inline void wrap_strncpy_dst_diff_max (char *d, const char *s, ptrdiff_t i, size_t n)
 {
   strncpy (d + i, s, n);   /* { dg-warning "offset -\[0-9\]+ is out of the bounds \\\[0, 45] of object .ar9. with type .(struct )?Array." "strncpy" } */
 }
@@ -186,8 +186,7 @@ void call_strncpy_dst_diff_max (const ch
   sink (&ar9);
 }
 
-void wrap_strncpy_dstarray_diff_neg (char *d, const char *s, ptrdiff_t i,
-				     size_t n)
+static inline void wrap_strncpy_dstarray_diff_neg (char *d, const char *s, ptrdiff_t i, size_t n)
 {
   strncpy (d + i, s, n);   /* { dg-warning "offset -\[0-9\]+ is out of the bounds \\\[0, 90] of object .ar10. with type .(struct )?Array ?\\\[2]." "strncpy" } */
 }


	Jakub

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2018-02-23 16:49 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-30 23:37 [PATCH] correct -Wrestrict handling of arrays of arrays (PR 84095) Martin Sebor
2018-02-01 23:45 ` Martin Sebor
2018-02-09  2:46   ` Martin Sebor
2018-02-14  6:14   ` Jeff Law
2018-02-15 17:48     ` Martin Sebor
2018-02-16 23:39       ` Jeff Law
2018-02-23  3:17   ` Siddhesh Poyarekar
2018-02-23 15:52     ` Martin Sebor
2018-02-23 16:19       ` Siddhesh Poyarekar
2018-02-23 16:49       ` Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).