aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2021-08-24 10:49:11 -0600
committerMartin Sebor <msebor@redhat.com>2021-08-24 10:49:11 -0600
commit820f0940d7ace1306430a9dcf1bd9577508a7a7e (patch)
treeb9517cd7a654bf06337532a5395539c4eaa6c55e /gcc
parent6d692ef43b2b3368c92c3fb757c7884fc94ee627 (diff)
downloadgcc-820f0940d7ace1306430a9dcf1bd9577508a7a7e.zip
gcc-820f0940d7ace1306430a9dcf1bd9577508a7a7e.tar.gz
gcc-820f0940d7ace1306430a9dcf1bd9577508a7a7e.tar.bz2
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/gimple-ssa-warn-access.cc20
-rw-r--r--gcc/pointer-query.cc105
-rw-r--r--gcc/testsuite/g++.dg/pr100574.C4
-rw-r--r--gcc/testsuite/g++.dg/warn/Warray-bounds-26.C27
-rw-r--r--gcc/testsuite/gcc.dg/Warray-bounds-88.c134
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overread.c32
-rw-r--r--gcc/testsuite/gcc.dg/pr20126.c6
-rw-r--r--gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c39
8 files changed, 286 insertions, 81 deletions
diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index 4a2dd9a..5df97a6 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 99caf78..ba8f8a9 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 42ba040..0df62aa 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 0000000..f72ac9d
--- /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 0000000..8cee8d2
--- /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 0343e43..7db7402 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 a421ce1..10aeec7 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 2afd2b5..846e930 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]; };