public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-3124] Reset PHI base0 flag if it's clear in any argument [PR101977, ...]
@ 2021-08-24 16:49 Martin Sebor
  0 siblings, 0 replies; only message in thread
From: Martin Sebor @ 2021-08-24 16:49 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:820f0940d7ace1306430a9dcf1bd9577508a7a7e

commit r12-3124-g820f0940d7ace1306430a9dcf1bd9577508a7a7e
Author: Martin Sebor <msebor@redhat.com>
Date:   Tue Aug 24 10:49:11 2021 -0600

    Reset PHI base0 flag if it's clear in any argument [PR101977, ...]
    
    Resolves:
    PR middle-end/101600 - Spurious -Warray-bounds downcasting a polymorphic pointer
    PR middle-end/101977 - bogus -Warray-bounds on a negative index into a parameter in conditional with null
    
    gcc/ChangeLog:
    
            PR middle-end/101600
            PR middle-end/101977
            * gimple-ssa-warn-access.cc (maybe_warn_for_bound): Tighten up
            the phrasing of a warning.
            (check_access): Use the remaining size after subtracting any offset
            rather than the whole object size.
            * pointer-query.cc (access_ref::get_ref): Clear BASE0 flag if it's
            clear for any nonnull PHI argument.
            (compute_objsize): Clear argument.
    
    gcc/testsuite/ChangeLog:
    
            PR middle-end/101600
            PR middle-end/101977
            * g++.dg/pr100574.C: Prune out valid warning.
            * gcc.dg/pr20126.c: Same.
            * gcc.dg/Wstringop-overread.c: Adjust text of expected warnings.
            Add new instances.
            * gcc.dg/warn-strnlen-no-nul.c: Same.
            * g++.dg/warn/Warray-bounds-26.C: New test.
            * gcc.dg/Warray-bounds-88.c: New test.

Diff:
---
 gcc/gimple-ssa-warn-access.cc                |  20 +++-
 gcc/pointer-query.cc                         | 105 ++++++++++++---------
 gcc/testsuite/g++.dg/pr100574.C              |   4 +
 gcc/testsuite/g++.dg/warn/Warray-bounds-26.C |  27 ++++++
 gcc/testsuite/gcc.dg/Warray-bounds-88.c      | 134 +++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/Wstringop-overread.c    |  32 +++----
 gcc/testsuite/gcc.dg/pr20126.c               |   6 ++
 gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c   |  39 ++++----
 8 files changed, 286 insertions(+), 81 deletions(-)

diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index 4a2dd9ade77..5df97a6473a 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -704,6 +704,15 @@ maybe_warn_for_bound (opt_code opt, location_t loc, GimpleOrTree exp, tree func,
   if (opt == OPT_Wstringop_overread)
     {
       bool maybe = pad && pad->src.phi ();
+      if (maybe)
+	{
+	  /* Issue a "maybe" warning only if the PHI refers to objects
+	     at least one of which has more space remaining than the bound.
+	     Otherwise, if the bound is greater, use the definitive form.  */
+	  offset_int remmax = pad->src.size_remaining ();
+	  if (remmax < wi::to_offset (bndrng[0]))
+	    maybe = false;
+	}
 
       if (tree_int_cst_lt (maxobjsize, bndrng[0]))
 	{
@@ -788,6 +797,15 @@ maybe_warn_for_bound (opt_code opt, location_t loc, GimpleOrTree exp, tree func,
     }
 
   bool maybe = pad && pad->dst.phi ();
+  if (maybe)
+    {
+      /* Issue a "maybe" warning only if the PHI refers to objects
+	 at least one of which has more space remaining than the bound.
+	 Otherwise, if the bound is greater, use the definitive form.  */
+      offset_int remmax = pad->dst.size_remaining ();
+      if (remmax < wi::to_offset (bndrng[0]))
+	maybe = false;
+    }
   if (tree_int_cst_lt (maxobjsize, bndrng[0]))
     {
       if (bndrng[0] == bndrng[1])
@@ -1418,7 +1436,7 @@ check_access (GimpleOrTree exp, tree dstwrite,
       location_t loc = get_location (exp);
       tree size = dstsize;
       if (pad && pad->mode == access_read_only)
-	size = wide_int_to_tree (sizetype, pad->src.sizrng[1]);
+	size = wide_int_to_tree (sizetype, pad->src.size_remaining ());
 
       if (range[0] && maxread && tree_fits_uhwi_p (size))
 	{
diff --git a/gcc/pointer-query.cc b/gcc/pointer-query.cc
index 99caf78bfa7..ba8f8a9dc69 100644
--- a/gcc/pointer-query.cc
+++ b/gcc/pointer-query.cc
@@ -634,10 +634,10 @@ access_ref::phi () const
   return as_a <gphi *> (def_stmt);
 }
 
-/* Determine and return the largest object to which *THIS.  If *THIS
-   refers to a PHI and PREF is nonnull, fill *PREF with the details
-   of the object determined by compute_objsize(ARG, OSTYPE) for each
-   PHI argument ARG.  */
+/* Determine and return the largest object to which *THIS refers.  If
+   *THIS refers to a PHI and PREF is nonnull, fill *PREF with the details
+   of the object determined by compute_objsize(ARG, OSTYPE) for each PHI
+   argument ARG.  */
 
 tree
 access_ref::get_ref (vec<access_ref> *all_refs,
@@ -659,21 +659,25 @@ access_ref::get_ref (vec<access_ref> *all_refs,
   if (!psnlim->visit_phi (ref))
     return NULL_TREE;
 
-  /* Reflects the range of offsets of all PHI arguments refer to the same
-     object (i.e., have the same REF).  */
-  access_ref same_ref;
-  /* The conservative result of the PHI reflecting the offset and size
-     of the largest PHI argument, regardless of whether or not they all
-     refer to the same object.  */
   pointer_query empty_qry;
   if (!qry)
     qry = &empty_qry;
 
+  /* The conservative result of the PHI reflecting the offset and size
+     of the largest PHI argument, regardless of whether or not they all
+     refer to the same object.  */
   access_ref phi_ref;
   if (pref)
     {
+      /* The identity of the object has not been determined yet but
+	 PREF->REF is set by the caller to the PHI for convenience.
+	 The size is negative/invalid and the offset is zero (it's
+	 updated only after the identity of the object has been
+	 established).  */
+      gcc_assert (pref->sizrng[0] < 0);
+      gcc_assert (pref->offrng[0] == 0 && pref->offrng[1] == 0);
+
       phi_ref = *pref;
-      same_ref = *pref;
     }
 
   /* Set if any argument is a function array (or VLA) parameter not
@@ -682,8 +686,6 @@ access_ref::get_ref (vec<access_ref> *all_refs,
   /* The size of the smallest object referenced by the PHI arguments.  */
   offset_int minsize = 0;
   const offset_int maxobjsize = wi::to_offset (max_object_size ());
-  /* The offset of the PHI, not reflecting those of its arguments.  */
-  const offset_int orng[2] = { phi_ref.offrng[0], phi_ref.offrng[1] };
 
   const unsigned nargs = gimple_phi_num_args (phi_stmt);
   for (unsigned i = 0; i < nargs; ++i)
@@ -695,28 +697,31 @@ access_ref::get_ref (vec<access_ref> *all_refs,
 	/* A PHI with all null pointer arguments.  */
 	return NULL_TREE;
 
-      /* Add PREF's offset to that of the argument.  */
-      phi_arg_ref.add_offset (orng[0], orng[1]);
       if (TREE_CODE (arg) == SSA_NAME)
 	qry->put_ref (arg, phi_arg_ref);
 
       if (all_refs)
 	all_refs->safe_push (phi_arg_ref);
 
-      const bool arg_known_size = (phi_arg_ref.sizrng[0] != 0
-				   || phi_arg_ref.sizrng[1] != maxobjsize);
-
       parmarray |= phi_arg_ref.parmarray;
 
       const bool nullp = integer_zerop (arg) && (i || i + 1 < nargs);
 
       if (phi_ref.sizrng[0] < 0)
 	{
+	  /* If PHI_REF doesn't contain a meaningful result yet set it
+	     to the result for the first argument.  */
 	  if (!nullp)
-	    same_ref = phi_arg_ref;
-	  phi_ref = phi_arg_ref;
+	    phi_ref = phi_arg_ref;
+
+	  /* Set if the current argument refers to one or more objects of
+	     known size (or range of sizes), as opposed to referring to
+	     one or more unknown object(s).  */
+	  const bool arg_known_size = (phi_arg_ref.sizrng[0] != 0
+				       || phi_arg_ref.sizrng[1] != maxobjsize);
 	  if (arg_known_size)
 	    minsize = phi_arg_ref.sizrng[0];
+
 	  continue;
 	}
 
@@ -740,8 +745,10 @@ access_ref::get_ref (vec<access_ref> *all_refs,
       offset_int phirem[2];
       phirem[1] = phi_ref.size_remaining (phirem);
 
-      if (phi_arg_ref.ref != same_ref.ref)
-	same_ref.ref = NULL_TREE;
+      /* Reset the PHI's BASE0 flag if any of the nonnull arguments
+	 refers to an object at an unknown offset.  */
+      if (!phi_arg_ref.base0)
+	phi_ref.base0 = false;
 
       if (phirem[1] < argrem[1]
 	  || (phirem[1] == argrem[1]
@@ -749,32 +756,13 @@ access_ref::get_ref (vec<access_ref> *all_refs,
 	/* Use the argument with the most space remaining as the result,
 	   or the larger one if the space is equal.  */
 	phi_ref = phi_arg_ref;
-
-      /* Set SAME_REF.OFFRNG to the maximum range of all arguments.  */
-      if (phi_arg_ref.offrng[0] < same_ref.offrng[0])
-	same_ref.offrng[0] = phi_arg_ref.offrng[0];
-      if (same_ref.offrng[1] < phi_arg_ref.offrng[1])
-	same_ref.offrng[1] = phi_arg_ref.offrng[1];
     }
 
-  if (!same_ref.ref && same_ref.offrng[0] != 0)
-    /* Clear BASE0 if not all the arguments refer to the same object and
-       if not all their offsets are zero-based.  This allows the final
-       PHI offset to out of bounds for some arguments but not for others
-       (or negative even of all the arguments are BASE0), which is overly
-       permissive.  */
-    phi_ref.base0 = false;
-
-  if (same_ref.ref)
-    phi_ref = same_ref;
-  else
-    {
-      /* Replace the lower bound of the largest argument with the size
-	 of the smallest argument, and set PARMARRAY if any argument
-	 was one.  */
-      phi_ref.sizrng[0] = minsize;
-      phi_ref.parmarray = parmarray;
-    }
+  /* Replace the lower bound of the largest argument with the size
+     of the smallest argument, and set PARMARRAY if any argument
+     was one.  */
+  phi_ref.sizrng[0] = minsize;
+  phi_ref.parmarray = parmarray;
 
   if (phi_ref.sizrng[0] < 0)
     {
@@ -804,6 +792,14 @@ access_ref::size_remaining (offset_int *pmin /* = NULL */) const
   if (!pmin)
     pmin = &minbuf;
 
+  if (sizrng[0] < 0)
+    {
+      /* If the identity of the object hasn't been determined return
+	 the maximum size range.  */
+      *pmin = 0;
+      return wi::to_offset (max_object_size ());
+    }
+
   /* add_offset() ensures the offset range isn't inverted.  */
   gcc_checking_assert (offrng[0] <= offrng[1]);
 
@@ -1597,6 +1593,11 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref,
     {
       pref->ref = ptr;
 
+      /* Reset the offset in case it was set by a prior call and not
+	 cleared by the caller.  The offset is only adjusted after
+	 the identity of the object has been determined.  */
+      pref->offrng[0] = pref->offrng[1] = 0;
+
       if (!addr && POINTER_TYPE_P (TREE_TYPE (ptr)))
 	{
 	  /* Set the maximum size if the reference is to the pointer
@@ -1607,6 +1608,9 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref,
 	  return true;
 	}
 
+      /* Valid offsets into the object are nonnegative.  */
+      pref->base0 = true;
+
       if (tree size = decl_init_size (ptr, false))
 	if (TREE_CODE (size) == INTEGER_CST)
 	  {
@@ -1960,6 +1964,11 @@ compute_objsize (tree ptr, int ostype, access_ref *pref,
 {
   pointer_query qry;
   qry.rvals = rvals;
+
+  /* Clear and invalidate in case *PREF is being reused.  */
+  pref->offrng[0] = pref->offrng[1] = 0;
+  pref->sizrng[0] = pref->sizrng[1] = -1;
+
   ssa_name_limit_t snlim;
   if (!compute_objsize_r (ptr, ostype, pref, snlim, &qry))
     return NULL_TREE;
@@ -1982,6 +1991,10 @@ compute_objsize (tree ptr, int ostype, access_ref *pref, pointer_query *ptr_qry)
   else
     ptr_qry = &qry;
 
+  /* Clear and invalidate in case *PREF is being reused.  */
+  pref->offrng[0] = pref->offrng[1] = 0;
+  pref->sizrng[0] = pref->sizrng[1] = -1;
+
   ssa_name_limit_t snlim;
   if (!compute_objsize_r (ptr, ostype, pref, snlim, ptr_qry))
     return NULL_TREE;
diff --git a/gcc/testsuite/g++.dg/pr100574.C b/gcc/testsuite/g++.dg/pr100574.C
index 42ba0404a28..0df62aa70ad 100644
--- a/gcc/testsuite/g++.dg/pr100574.C
+++ b/gcc/testsuite/g++.dg/pr100574.C
@@ -40,6 +40,8 @@ template <typename _Tp, typename _Alloc>
 template <typename...>
 void vector<_Tp, _Alloc>::_M_realloc_insert() {
   __alloc_traits::pointer __trans_tmp_5;
+  /* __len is used uninitialized below, which might trigger warnings,
+     even without -Wall (and other than -Wuninitialized).  */
   long __len(__len || max_size()), __elems_before;
   __trans_tmp_5 = _M_allocate___n
     ? __alloc_traits::allocate(_M_impl, _M_allocate___n)
@@ -62,3 +64,5 @@ void ReadTrackChunk()
     case MIDIST_PITCHBEND:
       block.data.push_back();
 }
+
+// { dg-prune-output "warning" }
diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-26.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-26.C
new file mode 100644
index 00000000000..f72ac9d4b51
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-26.C
@@ -0,0 +1,27 @@
+/* PR middle-end/101600 - Spurious -Warray-bounds downcasting a polymorphic
+   pointer
+   { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+struct S1 { virtual ~S1(); };
+struct S2 { int m; };
+struct S3 { virtual ~S3(); };
+struct S4: S1, S2, S3 {};
+
+int f1 ();
+
+void f2 (S3 *);
+
+void f3 (S2 *p)
+{
+  for (int i = f1 (); f1 (); )
+    {
+      if (i == 0)
+  	{
+  	  p = 0;
+  	  break;
+  	}
+    }
+
+  f2 (static_cast<S4 *>(p));  // { dg-bogus "-Warray-bounds" }
+}
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-88.c b/gcc/testsuite/gcc.dg/Warray-bounds-88.c
new file mode 100644
index 00000000000..8cee8d28571
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-88.c
@@ -0,0 +1,134 @@
+/* PR middle-end/101977 - bogus -Warray-bounds on a negative index into
+   a parameter in conditional with null
+   { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+struct A { int i; };
+struct B { struct A a1; struct A a2; };
+
+
+void nowarn_p_0_0 (struct A *p, int i)
+{
+  struct A *q = i < 0 ? p : 0 < i ? (struct A*)0 : 0;
+  struct B *r = (struct B*)((char *)q - __builtin_offsetof (struct B, a2));
+  r->a1.i = 0;
+}
+
+void nowarn_0_p_0 (struct A *p, int i)
+{
+  struct A *q = i < 0 ? 0 : 0 < i ? p : 0;
+  struct B *r = (struct B*)((char *)q - __builtin_offsetof (struct B, a2));
+  r->a1.i = 0;      // { dg-bogus "-Warray-bounds" }
+}
+
+void nowarn_0_0_p (struct A *p, int i)
+{
+  struct A *q = i < 0 ? 0 : 0 < i ? 0 : p;
+  struct B *r = (struct B*)((char *)q - __builtin_offsetof (struct B, a2));
+  r->a1.i = 0;      // { dg-bogus "-Warray-bounds" }
+}
+
+
+void nowarn_p_q_0 (struct A *p, struct A *q, int i)
+{
+  struct A *r = i < 0 ? p : 0 < i ? q : 0;
+  struct B *s = (struct B*)((char *)r - __builtin_offsetof (struct B, a2));
+  s->a1.i = 0;      // { dg-bogus "-Warray-bounds" }
+}
+
+void nowarn_p_0_q (struct A *p, struct A *q, int i)
+{
+  struct A *r = i < 0 ? p : 0 < i ? 0 : q;
+  struct B *s = (struct B*)((char *)r - __builtin_offsetof (struct B, a2));
+  s->a1.i = 0;      // { dg-bogus "-Warray-bounds" }
+}
+
+void nowarn_0_p_q (struct A *p, struct A *q, int i)
+{
+  struct A *r = i < 0 ? 0 : 0 < i ? p : q;
+  struct B *s = (struct B*)((char *)r - __builtin_offsetof (struct B, a2));
+  s->a1.i = 0;
+}
+
+
+void nowarn_p_q_r (struct A *p, struct A *q, struct A *r, int i)
+{
+  struct A *s = i < 0 ? p : 0 < i ? q : r;
+  struct B *t = (struct B*)((char *)s - __builtin_offsetof (struct B, a2));
+  t->a1.i = 0;
+}
+
+
+extern struct B b1, b2, b3;
+
+void nowarn_p_b1_0 (struct A *p, int i)
+{
+  struct A *r = i < 0 ? p : 0 < i ? &b1.a2 : 0;
+  struct B *s = (struct B*)((char *)r - __builtin_offsetof (struct B, a2));
+  s->a1.i = 0;      // { dg-bogus "-Warray-bounds" }
+}
+
+void nowarn_p_0_b1 (struct A *p, int i)
+{
+  struct A *r = i < 0 ? p : 0 < i ? 0 : &b1.a2;
+  struct B *s = (struct B*)((char *)r - __builtin_offsetof (struct B, a2));
+  s->a1.i = 0;      // { dg-bogus "-Warray-bounds" }
+}
+
+void nowarn_0_p_b1 (struct A *p, int i)
+{
+  struct A *r = i < 0 ? 0 : 0 < i ? p : &b1.a2;
+  struct B *s = (struct B*)((char *)r - __builtin_offsetof (struct B, a2));
+  s->a1.i = 0;
+}
+
+
+void nowarn_p_b1_b2 (struct A *p, int i)
+{
+  struct A *s = i < 0 ? p : 0 < i ? &b1.a2 : &b2.a2;
+  struct B *t = (struct B*)((char *)s - __builtin_offsetof (struct B, a2));
+  t->a1.i = 0;
+}
+
+void nowarn_b1_p_b2 (struct A *p, int i)
+{
+  struct A *s = i < 0 ? &b1.a2 : 0 < i ? p : &b2.a2;
+  struct B *t = (struct B*)((char *)s - __builtin_offsetof (struct B, a2));
+  t->a1.i = 0;
+}
+
+void nowarn_b1_b2_p (struct A *p, int i)
+{
+  struct A *s = i < 0 ? &b1.a2 : 0 < i ? &b2.a2 : p;
+  struct B *t = (struct B*)((char *)s - __builtin_offsetof (struct B, a2));
+  t->a1.i = 0;
+}
+
+void nowarn_b1_b2_b3 (struct A *p, int i)
+{
+  struct A *s = i < 0 ? &b1.a2 : 0 < i ? &b2.a2 : &b3.a2;
+  struct B *t = (struct B*)((char *)s - __builtin_offsetof (struct B, a2));
+  t->a1.i = 0;
+}
+
+
+void nowarn_0_b1_b2 (int i)
+{
+  struct A *s = i < 0 ? 0 : 0 < i ? &b1.a2 : &b2.a2;
+  struct B *t = (struct B*)((char *)s - __builtin_offsetof (struct B, a2));
+  t->a1.i = 0;
+}
+
+void warn_b1_0_b2 (int i)
+{
+  struct A *s = i < 0 ? &b1.a2 : 0 < i ? 0 : &b2.a2;
+  struct B *t = (struct B*)((char *)s - __builtin_offsetof (struct B, a2));
+  t->a1.i = 0;
+}
+
+void warn_b1_b2_0 (int i)
+{
+  struct A *s = i < 0 ? &b1.a2 : 0 < i ? &b2.a2 : 0;
+  struct B *t = (struct B*)((char *)s - __builtin_offsetof (struct B, a2));
+  t->a1.i = 0;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overread.c b/gcc/testsuite/gcc.dg/Wstringop-overread.c
index 0343e43cce4..7db74029819 100644
--- a/gcc/testsuite/gcc.dg/Wstringop-overread.c
+++ b/gcc/testsuite/gcc.dg/Wstringop-overread.c
@@ -317,9 +317,9 @@ void test_strnlen_array (int i, int i0, unsigned n)
   T (strnlen (a1, n));
 
   T (strnlen (a1 + 1, 0));
-  T (strnlen (a1 + 1, 1));      // { dg-warning "'strnlen' reading 1 byte from a region of size 0" }
+  T (strnlen (a1 + 1, 1));      // { dg-warning "'strnlen' specified bound 1 exceeds source size 0" }
   T (strnlen (a1 + 1, i0));
-  T (strnlen (a1 + 1, i0 + 1)); // { dg-warning "'strnlen' reading between 1 and \[0-9\]+ bytes from a region of size 0" }
+  T (strnlen (a1 + 1, i0 + 1)); // { dg-warning "'strnlen' specified bound \\\[1, \\d+] exceeds source size 0" }
   T (strnlen (a1 + 1, n));
   T (strnlen (a1 + i, 0));
   T (strnlen (a1 + i, 1));
@@ -335,7 +335,7 @@ void test_strnlen_array (int i, int i0, unsigned n)
   T (strnlen (a1 + i0, 2));     // { dg-warning "'strnlen' specified bound 2 exceeds source size 1" }
   T (strnlen (a1 + i0, n));
   T (strnlen (a1 + i0 + 1, 0));
-  T (strnlen (a1 + i0 + 1, 1)); // { dg-warning "'strnlen' reading 1 byte from a region of size 0" }
+  T (strnlen (a1 + i0 + 1, 1)); // { dg-warning "'strnlen' specified bound 1 exceeds source size 0" }
   T (strnlen (a1 + i0 + 1, n));
 
   T (strnlen (a2, 0));
@@ -344,10 +344,10 @@ void test_strnlen_array (int i, int i0, unsigned n)
   T (strnlen (a2, n));
   T (strnlen (a2 + 1, 0));
   T (strnlen (a2 + 1, 1));
-  T (strnlen (a2 + 1, 2));      // { dg-warning "'strnlen' specified bound 2 exceeds source size 1"  "pr87492" { xfail *-*-* } }
+  T (strnlen (a2 + 1, 2));      // { dg-warning "'strnlen' specified bound 2 exceeds source size 1"  "pr87492" }
   T (strnlen (a2 + 1, n));
   T (strnlen (a2 + 2, 0));
-  T (strnlen (a2 + 2, 1));      // { dg-warning "'strnlen' reading 1 byte from a region of size 0" }
+  T (strnlen (a2 + 2, 1));      // { dg-warning "'strnlen' specified bound 1 exceeds source size 0" }
   T (strnlen (a2 + 2, n));
   T (strnlen (a2 + i, 0));
   T (strnlen (a2 + i, 1));
@@ -365,13 +365,13 @@ void test_strnlen_array (int i, int i0, unsigned n)
 
   T (strnlen (a2 + i0 + 1, 0));
   T (strnlen (a2 + i0 + 1, 1));
-  T (strnlen (a2 + i0 + 1, 2));
+  T (strnlen (a2 + i0 + 1, 2)); // { dg-warning "'strnlen' specified bound 2 exceeds source size 1" }
   T (strnlen (a2 + i0 + 1, n));
 
   T (strnlen (a2 + i0 + 2, 0));
-  T (strnlen (a2 + i0 + 2, 1)); // { dg-warning "'strnlen' reading 1 byte from a region of size 0" }
+  T (strnlen (a2 + i0 + 2, 1)); // { dg-warning "'strnlen' specified bound 1 exceeds source size 0" }
   T (strnlen (a2 + i0 + 2, i0));
-  T (strnlen (a2 + i0 + 2, i0 + 1)); // { dg-warning "'strnlen' reading between 1 and \[0-9\]+ bytes from a region of size 0" }
+  T (strnlen (a2 + i0 + 2, i0 + 1)); // { dg-warning "'strnlen' specified bound \\\[1, \\d+] exceeds source size 0" }
   T (strnlen (a2 + i0 + 2, n));
 }
 
@@ -512,9 +512,9 @@ void test_strndup_array (int i, int i0, unsigned n)
   T (strndup (a1, 2));          // { dg-warning "'strndup' specified bound 2 exceeds source size 1" }
   T (strndup (a1, n));
   T (strndup (a1 + 1, 0));
-  T (strndup (a1 + 1, 1));      // { dg-warning "'strndup' reading 1 byte from a region of size 0" }
+  T (strndup (a1 + 1, 1));      // { dg-warning "'strndup' specified bound 1 exceeds source size 0" }
   T (strndup (a1 + 1, i0));
-  T (strndup (a1 + 1, i0 + 1)); // { dg-warning "'strndup' reading between 1 and \[0-9\]+ bytes from a region of size 0" }
+  T (strndup (a1 + 1, i0 + 1)); // { dg-warning "'strndup' specified bound \\\[1, \\d+] exceeds source size 0" }
   T (strndup (a1 + 1, n));
   T (strndup (a1 + i, 0));
   T (strndup (a1 + i, 1));
@@ -529,7 +529,7 @@ void test_strndup_array (int i, int i0, unsigned n)
   T (strndup (a1 + i0, 1));
   T (strndup (a1 + i0, n));
   T (strndup (a1 + i0 + 1, 0));
-  T (strndup (a1 + i0 + 1, 1)); // { dg-warning "'strndup' reading 1 byte from a region of size 0" }
+  T (strndup (a1 + i0 + 1, 1)); // { dg-warning "'strndup' specified bound 1 exceeds source size 0" }
   T (strndup (a1 + i0 + 1, n));
 
   T (strndup (a2, 0));
@@ -538,10 +538,10 @@ void test_strndup_array (int i, int i0, unsigned n)
   T (strndup (a2, n));
   T (strndup (a2 + 1, 0));
   T (strndup (a2 + 1, 1));
-  T (strndup (a2 + 1, 2));
+  T (strndup (a2 + 1, 2));      // { dg-warning "'strndup' specified bound 2 exceeds source size 1" }
   T (strndup (a2 + 1, n));
   T (strndup (a2 + 2, 0));
-  T (strndup (a2 + 2, 1));      // { dg-warning "'strndup' reading 1 byte from a region of size 0" }
+  T (strndup (a2 + 2, 1));      // { dg-warning "'strndup' specified bound 1 exceeds source size 0" }
   T (strndup (a2 + 2, n));
   T (strndup (a2 + i, 0));
   T (strndup (a2 + i, 1));
@@ -559,13 +559,13 @@ void test_strndup_array (int i, int i0, unsigned n)
 
   T (strndup (a2 + i0 + 1, 0));
   T (strndup (a2 + i0 + 1, 1));
-  T (strndup (a2 + i0 + 1, 2));
+  T (strndup (a2 + i0 + 1, 2)); // { dg-warning "'strndup' specified bound 2 exceeds source size 1" }
   T (strndup (a2 + i0 + 1, n));
 
   T (strndup (a2 + i0 + 2, 0));
-  T (strndup (a2 + i0 + 2, 1)); // { dg-warning "'strndup' reading 1 byte from a region of size 0" }
+  T (strndup (a2 + i0 + 2, 1)); // { dg-warning "'strndup' specified bound 1 exceeds source size 0" }
   T (strndup (a2 + i0 + 2, i0));
-  T (strndup (a2 + i0 + 2, i0 + 1)); // { dg-warning "'strndup' reading between 1 and \[0-9\]+ bytes from a region of size 0" }
+  T (strndup (a2 + i0 + 2, i0 + 1)); // { dg-warning "'strndup' specified bound \\\[1, \\d+] exceeds source size 0" }
   T (strndup (a2 + i0 + 2, n));
 }
 
diff --git a/gcc/testsuite/gcc.dg/pr20126.c b/gcc/testsuite/gcc.dg/pr20126.c
index a421ce1758d..10aeec74f39 100644
--- a/gcc/testsuite/gcc.dg/pr20126.c
+++ b/gcc/testsuite/gcc.dg/pr20126.c
@@ -34,6 +34,10 @@ foo (S *x, S *y)
   while (e <= g)
     {
       const char *t = e + 1;
+      /* The pointer E below increases but the bound H stays constant,
+	 letting the latter exceed the size remaining in the argument
+	 pointed to by the formed, which might be detected by
+	 -Wstringop-overread.  */
       if (__builtin_memcmp (e, f, h) == 0)
         return 1;
       e = t;
@@ -48,3 +52,5 @@ main (void)
     abort ();
   return 0;
 }
+
+/* { dg-prune-output "-Wstringop-overread" } */
diff --git a/gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c b/gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c
index 2afd2b5feeb..846e9300750 100644
--- a/gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c
+++ b/gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c
@@ -143,14 +143,17 @@ T (v0 ? b[1] : "", bsz);
 T (v0 ? b[2] : "", bsz);
 T (v0 ? b[3] : "", bsz);
 
-T (v0 ? "" : b[0], bsz + 1);      /* { dg-warning "bound 6 may exceed source size 5" } */
-T (v0 ? "" : b[1], bsz + 1);
-T (v0 ? "" : b[2], bsz + 1);
-T (v0 ? "" : b[3], bsz + 1);      /* { dg-warning "unterminated" "pr86937" { xfail *-*-* } } */
-T (v0 ? b[0] : "", bsz + 1);      /* { dg-warning "bound 6 may exceed source size 5" } */
-T (v0 ? b[1] : "", bsz + 1);
-T (v0 ? b[2] : "", bsz + 1);
-T (v0 ? b[3] : "", bsz + 1);      /* { dg-warning "unterminated" "pr86937" { xfail *-*-* } } */
+/* The warnings below are strictly correct but the strnlen calls are safe
+   because the reads are bounded by the length of the constant arguments.
+   It might make sense to relax the warning to avoid triggering for them.  */
+T (v0 ? "" : b[0], bsz + 1);      /* { dg-warning "bound 6 exceeds source size 5" } */
+T (v0 ? "" : b[1], bsz + 1);      /* { dg-warning "bound 6 exceeds source size 5" } */
+T (v0 ? "" : b[2], bsz + 1);      /* { dg-warning "bound 6 exceeds source size 5" } */
+T (v0 ? "" : b[3], bsz + 1);      /* { dg-warning "bound 6 exceeds source size 5" } */
+T (v0 ? b[0] : "", bsz + 1);      /* { dg-warning "bound 6 exceeds source size 5" } */
+T (v0 ? b[1] : "", bsz + 1);      /* { dg-warning "bound 6 exceeds source size 5" } */
+T (v0 ? b[2] : "", bsz + 1);      /* { dg-warning "bound 6 exceeds source size 5" } */
+T (v0 ? b[3] : "", bsz + 1);      /* { dg-warning "bound 6 exceeds source size 5" } */
 
 T (v0 ? "" : b[i0], bsz);
 T (v0 ? "" : b[i1], bsz);
@@ -164,11 +167,11 @@ T (v0 ? b[i3] : "", bsz);
 T (v0 ? "" : b[i0], bsz + 1);
 T (v0 ? "" : b[i1], bsz + 1);
 T (v0 ? "" : b[i2], bsz + 1);
-T (v0 ? "" : b[i3], bsz + 1);     /* { dg-warning "unterminated" "pr86937" { xfail *-*-* } } */
+T (v0 ? "" : b[i3], bsz + 1);     /* { dg-warning "bound 6 exceeds source size 5" "pr86937" } */
 T (v0 ? b[i0] : "", bsz + 1);
 T (v0 ? b[i1] : "", bsz + 1);
 T (v0 ? b[i2] : "", bsz + 1);
-T (v0 ? b[i3] : "", bsz + 1);     /* { dg-warning "unterminated" "pr86937" { xfail *-*-* } } */
+T (v0 ? b[i3] : "", bsz + 1);     /* { dg-warning "bound 6 exceeds source size 5" "pr86937" } */
 
 T (v0 ? "1234" : b[3], bsz);
 T (v0 ? "1234" : b[i3], bsz);
@@ -180,15 +183,15 @@ T (v0 ? b[0] : b[2], bsz);
 T (v0 ? b[2] : b[3], bsz);
 T (v0 ? b[3] : b[2], bsz);
 
-T (v0 ? "1234" : b[3], bsz + 1);  /* { dg-warning "unterminated" "pr86937" { xfail *-*-* } } */
-T (v0 ? "1234" : b[i3], bsz + 1); /* { dg-warning "unterminated" "pr86937" { xfail *-*-* } } */
-T (v0 ? b[3] : "1234", bsz + 1);  /* { dg-warning "unterminated" "pr86937" { xfail *-*-* } } */
-T (v0 ? b[i3] : "1234", bsz + 1); /* { dg-warning "unterminated" "pr86937" { xfail *-*-* } } */
+T (v0 ? "1234" : b[3], bsz + 1);  /* { dg-warning "bound 6 exceeds source size 5" } */
+T (v0 ? "1234" : b[i3], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */
+T (v0 ? b[3] : "1234", bsz + 1);  /* { dg-warning "bound 6 exceeds source size 5" } */
+T (v0 ? b[i3] : "1234", bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */
 
-T (v0 ? a : b[3], bsz + 1);       /* { dg-warning "bound 6 may exceed source size 5" "pr86937" { xfail *-*-*} } */
-T (v0 ? b[0] : b[2], bsz + 1);    /* { dg-warning "bound 6 may exceed source size 5" "pr86937" } */
-T (v0 ? b[2] : b[3], bsz + 1);    /* { dg-warning "unterminated" "pr86937" { xfail *-*-* } } */
-T (v0 ? b[3] : b[2], bsz + 1);    /* { dg-warning "unterminated" "pr86937" { xfail *-*-* } } */
+T (v0 ? a : b[3], bsz + 1);       /* { dg-warning "bound 6 exceeds source size 5" } */
+T (v0 ? b[0] : b[2], bsz + 1);    /* { dg-warning "bound 6 exceeds source size 5" } */
+T (v0 ? b[2] : b[3], bsz + 1);    /* { dg-warning "bound 6 exceeds source size 5" } */
+T (v0 ? b[3] : b[2], bsz + 1);    /* { dg-warning "bound 6 exceeds source size 5" } */
 
 struct A { char a[5], b[5]; };


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-08-24 16:49 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-24 16:49 [gcc r12-3124] Reset PHI base0 flag if it's clear in any argument [PR101977, ...] Martin Sebor

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).