]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Add -Wstringop-overread for reading past the end by string functions.
authorMartin Sebor <msebor@redhat.com>
Fri, 28 Aug 2020 19:13:28 +0000 (13:13 -0600)
committerMartin Sebor <msebor@redhat.com>
Fri, 28 Aug 2020 19:18:28 +0000 (13:18 -0600)
gcc/ChangeLog:

* attribs.c (init_attr_rdwr_indices): Use global access_mode.
* attribs.h (struct attr_access): Same.
* builtins.c (fold_builtin_strlen): Add argument.
(compute_objsize): Declare.
(get_range): Declare.
(check_read_access): New function.
(access_ref::access_ref): Define ctor.
(warn_string_no_nul): Add arguments.  Handle -Wstrintop-overread.
(check_nul_terminated_array): Handle source strings of different
ranges of sizes.
(expand_builtin_strlen): Remove warning code, call check_read_access
instead.  Declare locals closer to their initialization.
(expand_builtin_strnlen): Same.
(maybe_warn_for_bound): New function.
(warn_for_access): Remove argument.  Handle -Wstrintop-overread.
(inform_access): Change argument type.
(get_size_range): New function.
(check_access): Remove unused arguments.  Add new arguments.  Handle
-Wstrintop-overread.  Move warning code to helpers and call them.
Call check_nul_terminated_array.
(check_memop_access): Remove unnecessary and provide additional
arguments in calls.
(expand_builtin_memchr): Call check_read_access.
(expand_builtin_strcat): Remove unnecessary and provide additional
arguments in calls.
(expand_builtin_strcpy): Same.
(expand_builtin_strcpy_args): Same.  Avoid testing no-warning bit.
(expand_builtin_stpcpy_1): Remove unnecessary and provide additional
arguments in calls.
(expand_builtin_stpncpy): Same.
(check_strncat_sizes): Same.
(expand_builtin_strncat): Remove unnecessary and provide additional
arguments in calls.  Adjust comments.
(expand_builtin_strncpy): Remove unnecessary and provide additional
arguments in calls.
(expand_builtin_memcmp): Remove warning code.  Call check_access.
(expand_builtin_strcmp): Call check_access instead of
check_nul_terminated_array.
(expand_builtin_strncmp): Handle -Wstrintop-overread.
(expand_builtin_fork_or_exec): Call check_access instead of
check_nul_terminated_array.
(expand_builtin): Same.
(fold_builtin_1): Pass additional argument.
(fold_builtin_n): Same.
(fold_builtin_strpbrk): Remove calls to check_nul_terminated_array.
(expand_builtin_memory_chk): Add comments.
(maybe_emit_chk_warning): Remove unnecessary and provide additional
arguments in calls.
(maybe_emit_sprintf_chk_warning): Same.  Adjust comments.
* builtins.h (warn_string_no_nul): Add arguments.
(struct access_ref): Add member and ctor argument.
(struct access_data): Add members and ctor.
(check_access): Adjust signature.
* calls.c (maybe_warn_nonstring_arg): Return an indication of
whether a warning was issued.  Issue -Wstrintop-overread instead
of -Wstringop-overflow.
(append_attrname): Adjust to naming changes.
(maybe_warn_rdwr_sizes): Same.  Remove unnecessary and provide
additional arguments in calls.
* calls.h (maybe_warn_nonstring_arg): Return bool.
* doc/invoke.texi (-Wstringop-overread): Document new option.
* gimple-fold.c (gimple_fold_builtin_strcpy): Provide an additional
argument in call.
(gimple_fold_builtin_stpcpy): Same.
* tree-ssa-uninit.c (maybe_warn_pass_by_reference): Adjust to naming
changes.
* tree.h (enum access_mode): New type.

gcc/c-family/ChangeLog:

* c.opt (Wstringop-overread): New option.

gcc/testsuite/ChangeLog:

* c-c++-common/Warray-bounds-7.c: Adjust expected warnings.
* c-c++-common/Wrestrict.c: Remove xfail.
* c-c++-common/attr-nonstring-3.c: Adjust text of expected warnings.
* c-c++-common/attr-nonstring-6.c: Suppress -Wstringop-overread
instead of -Wstringop-overflow.
* c-c++-common/attr-nonstring-8.c: Adjust text of expected warnings.
* g++.dg/torture/Wsizeof-pointer-memaccess1.C: Also suppress
 -Wstringop-overread.
* g++.dg/torture/Wsizeof-pointer-memaccess2.C: Same.
* gcc.dg/Warray-bounds-39.c: Adjust expected warnings.
* gcc.dg/Warray-bounds-40.c: Also suppress -Wstringop-overread.
* gcc.dg/Warray-bounds-58.c: Remove xfail.  Also expect
-Wstringop-overread.  Adjust text of expected warnings.
* gcc.dg/Wsizeof-pointer-memaccess1.c: Also suppress
 -Wstringop-overread.
* gcc.dg/Wstringop-overflow-22.c: Adjust text of expected warnings.
* gcc.dg/Wstringop-overflow-33.c: Expect -Wstringop-overread.
* gcc.dg/Wstringop-overflow-9.c: Expect -Wstringop-overread.
* gcc.dg/attr-nonstring-2.c: Adjust text of expected warnings.
* gcc.dg/attr-nonstring-3.c: Same.
* gcc.dg/attr-nonstring-4.c: Same.
* gcc.dg/attr-nonstring.c: Expect -Wstringop-overread.
* gcc.dg/builtin-stringop-chk-5.c: Adjust comment.
* gcc.dg/builtin-stringop-chk-8.c: Enable -Wstringop-overread instead
of -Wstringop-overflow.
* gcc.dg/pr78902.c: Also expect -Wstringop-overread.
* gcc.dg/pr79214.c: Adjust text of expected warnings.
* gcc.dg/strcmpopt_10.c: Suppress valid -Wno-stringop-overread.
* gcc.dg/strlenopt-57.c: Also expect -Wstringop-overread.
* gcc.dg/torture/Wsizeof-pointer-memaccess1.c: Also suppress valid
-Wno-stringop-overread.
* gcc.dg/tree-ssa/builtins-folding-gimple-ub.c: Same.
* gcc.dg/uninit-33.c: Same.
* gcc.dg/warn-strnlen-no-nul-2.c: Adjust text of expected warning.
* gcc.dg/warn-strnlen-no-nul.c: Same.
* gcc.target/i386/strcmpopt_6.c: Suppress -Wstringop-overread.
* gcc.dg/Wstringop-overread-2.c: New test.
* gcc.dg/Wstringop-overread.c: New test.

43 files changed:
gcc/attribs.c
gcc/attribs.h
gcc/builtins.c
gcc/builtins.h
gcc/c-family/c.opt
gcc/calls.c
gcc/calls.h
gcc/doc/invoke.texi
gcc/gimple-fold.c
gcc/testsuite/c-c++-common/Warray-bounds-7.c
gcc/testsuite/c-c++-common/Wrestrict.c
gcc/testsuite/c-c++-common/attr-nonstring-3.c
gcc/testsuite/c-c++-common/attr-nonstring-6.c
gcc/testsuite/c-c++-common/attr-nonstring-8.c
gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess1.C
gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess2.C
gcc/testsuite/gcc.dg/Warray-bounds-39.c
gcc/testsuite/gcc.dg/Warray-bounds-40.c
gcc/testsuite/gcc.dg/Warray-bounds-58.c
gcc/testsuite/gcc.dg/Wsizeof-pointer-memaccess1.c
gcc/testsuite/gcc.dg/Wstringop-overflow-22.c
gcc/testsuite/gcc.dg/Wstringop-overflow-33.c
gcc/testsuite/gcc.dg/Wstringop-overflow-9.c
gcc/testsuite/gcc.dg/Wstringop-overread-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wstringop-overread.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/attr-nonstring-2.c
gcc/testsuite/gcc.dg/attr-nonstring-3.c
gcc/testsuite/gcc.dg/attr-nonstring-4.c
gcc/testsuite/gcc.dg/attr-nonstring.c
gcc/testsuite/gcc.dg/builtin-stringop-chk-5.c
gcc/testsuite/gcc.dg/builtin-stringop-chk-8.c
gcc/testsuite/gcc.dg/pr78902.c
gcc/testsuite/gcc.dg/pr79214.c
gcc/testsuite/gcc.dg/strcmpopt_10.c
gcc/testsuite/gcc.dg/strlenopt-57.c
gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c
gcc/testsuite/gcc.dg/tree-ssa/builtins-folding-gimple-ub.c
gcc/testsuite/gcc.dg/uninit-33.c
gcc/testsuite/gcc.dg/warn-strnlen-no-nul-2.c
gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c
gcc/testsuite/gcc.target/i386/strcmpopt_6.c
gcc/tree-ssa-uninit.c
gcc/tree.h

index 71dae123af841303d6f3c3f2ad5ca68a1eefc9ca..7c0c18ff108219ed038d19b4f395cfa9ac59fc91 100644 (file)
@@ -2045,10 +2045,10 @@ init_attr_rdwr_indices (rdwr_map *rwm, tree fntype)
 
          switch (*m)
            {
-           case 'r': acc.mode = acc.read_only; break;
-           case 'w': acc.mode = acc.write_only; break;
-           case 'x': acc.mode = acc.read_write; break;
-           case '-': acc.mode = acc.none; break;
+           case 'r': acc.mode = access_read_only; break;
+           case 'w': acc.mode = access_write_only; break;
+           case 'x': acc.mode = access_read_write; break;
+           case '-': acc.mode = access_none; break;
            default: gcc_unreachable ();
            }
 
index dea0b6c44e683c6b1d1c87fd97d38b23e676998f..6d0a9e48a8cd97707c5a470c366e2f52e0790623 100644 (file)
@@ -234,7 +234,6 @@ struct attr_access
   unsigned sizarg;
 
   /* The access mode.  */
-  enum access_mode { none, read_only, write_only, read_write };
   access_mode mode;
 };
 
index 8845816aebdd00670f520ddbaefb69019d848fd2..df121f98b95333c603c8b184bb766f85c352f3a5 100644 (file)
@@ -156,7 +156,7 @@ static rtx expand_builtin_expect (tree, rtx);
 static rtx expand_builtin_expect_with_probability (tree, rtx);
 static tree fold_builtin_constant_p (tree);
 static tree fold_builtin_classify_type (tree);
-static tree fold_builtin_strlen (location_t, tree, tree);
+static tree fold_builtin_strlen (location_t, tree, tree, tree);
 static tree fold_builtin_inf (location_t, tree, int);
 static tree rewrite_call_expr (location_t, tree, int, tree, int, ...);
 static bool validate_arg (const_tree, enum tree_code code);
@@ -183,6 +183,9 @@ static void maybe_emit_chk_warning (tree, enum built_in_function);
 static void maybe_emit_sprintf_chk_warning (tree, enum built_in_function);
 static void maybe_emit_free_warning (tree);
 static tree fold_builtin_object_size (tree, tree);
+static tree compute_objsize (tree, int, access_ref *, const vr_values * = NULL);
+static bool get_range (tree, signop, offset_int[2], const vr_values * = NULL);
+static bool check_read_access (tree, tree, tree = NULL_TREE, int = 1);
 
 unsigned HOST_WIDE_INT target_newline;
 unsigned HOST_WIDE_INT target_percent;
@@ -195,6 +198,26 @@ static tree do_mpfr_remquo (tree, tree, tree);
 static tree do_mpfr_lgamma_r (tree, tree, tree);
 static void expand_builtin_sync_synchronize (void);
 
+access_ref::access_ref (tree bound /* = NULL_TREE */,
+                       bool minaccess /* = false */)
+  : ref ()
+{
+  /* Set to valid.  */
+  offrng[0] = offrng[1] = 0;
+  /* Invalidate.   */
+  sizrng[0] = sizrng[1] = -1;
+
+  /* Set the default bounds of the access and adjust below.  */
+  bndrng[0] = minaccess ? 1 : 0;
+  bndrng[1] = HOST_WIDE_INT_M1U;
+
+  /* When BOUND is nonnull and a range can be extracted from it,
+     set the bounds of the access to reflect both it and MINACCESS.
+     BNDRNG[0] is the size of the minimum access.  */
+  if (bound && get_range (bound, UNSIGNED, bndrng))
+    bndrng[0] = bndrng[0] > 0 && minaccess ? 1 : 0;
+}
+
 /* Return true if NAME starts with __builtin_ or __sync_.  */
 
 static bool
@@ -543,38 +566,132 @@ string_length (const void *ptr, unsigned eltsize, unsigned maxelts)
   return n;
 }
 
-/* For a call at LOC to a function FN that expects a string in the argument
-   ARG, issue a diagnostic due to it being a called with an argument
-   declared at NONSTR that is a character array with no terminating NUL.  */
+/* For a call EXPR at LOC to a function FNAME that expects a string
+   in the argument ARG, issue a diagnostic due to it being a called
+   with an argument that is a character array with no terminating
+   NUL.  SIZE is the EXACT size of the array, and BNDRNG the number
+   of characters in which the NUL is expected.  Either EXPR or FNAME
+   may be null but noth both.  SIZE may be null when BNDRNG is null.  */
 
 void
-warn_string_no_nul (location_t loc, const char *fn, tree arg, tree decl)
+warn_string_no_nul (location_t loc, tree expr, const char *fname,
+                   tree arg, tree decl, tree size /* = NULL_TREE */,
+                   bool exact /* = false */,
+                   const wide_int bndrng[2] /* = NULL */)
 {
-  if (TREE_NO_WARNING (arg))
+  if ((expr && TREE_NO_WARNING (expr)) || TREE_NO_WARNING (arg))
     return;
 
   loc = expansion_point_location_if_in_system_header (loc);
+  bool warned;
+
+  /* Format the bound range as a string to keep the nuber of messages
+     from exploding.  */
+  char bndstr[80];
+  *bndstr = 0;
+  if (bndrng)
+    {
+      if (bndrng[0] == bndrng[1])
+       sprintf (bndstr, "%llu", (unsigned long long) bndrng[0].to_uhwi ());
+      else
+       sprintf (bndstr, "[%llu, %llu]",
+                (unsigned long long) bndrng[0].to_uhwi (),
+                (unsigned long long) bndrng[1].to_uhwi ());
+    }
+
+  const tree maxobjsize = max_object_size ();
+  const wide_int maxsiz = wi::to_wide (maxobjsize);
+  if (expr)
+    {
+      tree func = get_callee_fndecl (expr);
+      if (bndrng)
+       {
+         if (wi::ltu_p (maxsiz, bndrng[0]))
+           warned = warning_at (loc, OPT_Wstringop_overread,
+                                "%K%qD specified bound %s exceeds "
+                                "maximum object size %E",
+                                expr, func, bndstr, maxobjsize);
+         else
+           {
+             bool maybe = wi::to_wide (size) == bndrng[0];
+             warned = warning_at (loc, OPT_Wstringop_overread,
+                                  exact
+                                  ? G_("%K%qD specified bound %s exceeds "
+                                       "the size %E of unterminated array")
+                                  : (maybe
+                                     ? G_("%K%qD specified bound %s may "
+                                          "exceed the size of at most %E "
+                                          "of unterminated array")
+                                     : G_("%K%qD specified bound %s exceeds "
+                                          "the size of at most %E "
+                                          "of unterminated array")),
+                                  expr, func, bndstr, size);
+           }
+       }
+      else
+       warned = warning_at (loc, OPT_Wstringop_overread,
+                            "%K%qD argument missing terminating nul",
+                            expr, func);
+    }
+  else
+    {
+      if (bndrng)
+       {
+         if (wi::ltu_p (maxsiz, bndrng[0]))
+           warned = warning_at (loc, OPT_Wstringop_overread,
+                                "%qs specified bound %s exceeds "
+                                "maximum object size %E",
+                                fname, bndstr, maxobjsize);
+         else
+           {
+             bool maybe = wi::to_wide (size) == bndrng[0];
+             warned = warning_at (loc, OPT_Wstringop_overread,
+                                  exact
+                                  ? G_("%qs specified bound %s exceeds "
+                                       "the size %E of unterminated array")
+                                  : (maybe
+                                     ? G_("%qs specified bound %s may "
+                                          "exceed the size of at most %E "
+                                          "of unterminated array")
+                                     : G_("%qs specified bound %s exceeds "
+                                          "the size of at most %E "
+                                          "of unterminated array")),
+                                  fname, bndstr, size);
+           }
+       }
+      else
+       warned = warning_at (loc, OPT_Wstringop_overread,
+                            "%qsargument missing terminating nul",
+                            fname);
+    }
 
-  if (warning_at (loc, OPT_Wstringop_overflow_,
-                 "%qs argument missing terminating nul", fn))
+  if (warned)
     {
       inform (DECL_SOURCE_LOCATION (decl),
              "referenced argument declared here");
       TREE_NO_WARNING (arg) = 1;
+      if (expr)
+       TREE_NO_WARNING (expr) = 1;
     }
 }
 
 /* For a call EXPR (which may be null) that expects a string argument
-   and SRC as the argument, returns false if SRC is a character array
-   with no terminating NUL.  When nonnull, BOUND is the number of
-   characters in which to expect the terminating NUL.
-   When EXPR is nonnull also issues a warning.  */
+   SRC as an argument, returns false if SRC is a character array with
+   no terminating NUL.  When nonnull, BOUND is the number of characters
+   in which to expect the terminating NUL.  RDONLY is true for read-only
+   accesses such as strcmp, false for read-write such as strcpy.  When
+   EXPR is also issues a warning.  */
 
 bool
-check_nul_terminated_array (tree expr, tree src, tree bound /* = NULL_TREE */)
+check_nul_terminated_array (tree expr, tree src,
+                           tree bound /* = NULL_TREE */)
 {
+  /* The constant size of the array SRC points to.  The actual size
+     may be less of EXACT is true, but not more.  */
   tree size;
+  /* True if SRC involves a non-constant offset into the array.  */
   bool exact;
+  /* The unterminated constant array SRC points to.  */
   tree nonstr = unterminated_array (src, &size, &exact);
   if (!nonstr)
     return true;
@@ -583,28 +700,30 @@ check_nul_terminated_array (tree expr, tree src, tree bound /* = NULL_TREE */)
      is the constant size of the array in bytes.  EXACT is true when
      SIZE is exact.  */
 
+  wide_int bndrng[2];
   if (bound)
     {
-      wide_int min, max;
       if (TREE_CODE (bound) == INTEGER_CST)
-       min = max = wi::to_wide (bound);
+       bndrng[0] = bndrng[1] = wi::to_wide (bound);
       else
        {
-         value_range_kind rng = get_range_info (bound, &min, &max);
+         value_range_kind rng = get_range_info (bound, bndrng, bndrng + 1);
          if (rng != VR_RANGE)
            return true;
        }
 
-      if (wi::leu_p (min, wi::to_wide (size)))
+      if (exact)
+       {
+         if (wi::leu_p (bndrng[0], wi::to_wide (size)))
+           return true;
+       }
+      else if (wi::lt_p (bndrng[0], wi::to_wide (size), UNSIGNED))
        return true;
     }
 
-  if (expr && !TREE_NO_WARNING (expr))
-    {
-      tree fndecl = get_callee_fndecl (expr);
-      const char *fname = IDENTIFIER_POINTER (DECL_NAME (fndecl));
-      warn_string_no_nul (EXPR_LOCATION (expr), fname, src, nonstr);
-    }
+  if (expr)
+    warn_string_no_nul (EXPR_LOCATION (expr), expr, NULL, src, nonstr,
+                       size, exact, bound ? bndrng : NULL);
 
   return false;
 }
@@ -2998,19 +3117,12 @@ expand_builtin_strlen (tree exp, rtx target,
   if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
     return NULL_RTX;
 
-  class expand_operand ops[4];
-  rtx pat;
-  tree len;
   tree src = CALL_EXPR_ARG (exp, 0);
-  rtx src_reg;
-  rtx_insn *before_strlen;
-  machine_mode insn_mode;
-  enum insn_code icode = CODE_FOR_nothing;
-  unsigned int align;
+  if (!check_read_access (exp, src))
+    return NULL_RTX;
 
   /* If the length can be computed at compile-time, return it.  */
-  len = c_strlen (src, 0);
-  if (len)
+  if (tree len = c_strlen (src, 0))
     return expand_expr (len, target, target_mode, EXPAND_NORMAL);
 
   /* If the length can be computed at compile-time and is constant
@@ -3018,20 +3130,22 @@ expand_builtin_strlen (tree exp, rtx target,
      src for side-effects, then return len.
      E.g. x = strlen (i++ ? "xfoo" + 1 : "bar");
      can be optimized into: i++; x = 3;  */
-  len = c_strlen (src, 1);
+  tree len = c_strlen (src, 1);
   if (len && TREE_CODE (len) == INTEGER_CST)
     {
       expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
       return expand_expr (len, target, target_mode, EXPAND_NORMAL);
     }
 
-  align = get_pointer_alignment (src) / BITS_PER_UNIT;
+  unsigned int align = get_pointer_alignment (src) / BITS_PER_UNIT;
 
   /* If SRC is not a pointer type, don't do this operation inline.  */
   if (align == 0)
     return NULL_RTX;
 
   /* Bail out if we can't compute strlen in the right mode.  */
+  machine_mode insn_mode;
+  enum insn_code icode = CODE_FOR_nothing;
   FOR_EACH_MODE_FROM (insn_mode, target_mode)
     {
       icode = optab_handler (strlen_optab, insn_mode);
@@ -3044,12 +3158,13 @@ expand_builtin_strlen (tree exp, rtx target,
   /* Make a place to hold the source address.  We will not expand
      the actual source until we are sure that the expansion will
      not fail -- there are trees that cannot be expanded twice.  */
-  src_reg = gen_reg_rtx (Pmode);
+  rtx src_reg = gen_reg_rtx (Pmode);
 
   /* Mark the beginning of the strlen sequence so we can emit the
      source operand later.  */
-  before_strlen = get_last_insn ();
+  rtx_insn *before_strlen = get_last_insn ();
 
+  class expand_operand ops[4];
   create_output_operand (&ops[0], target, insn_mode);
   create_fixed_operand (&ops[1], gen_rtx_MEM (BLKmode, src_reg));
   create_integer_operand (&ops[2], 0);
@@ -3064,7 +3179,7 @@ expand_builtin_strlen (tree exp, rtx target,
 
   /* Now that we are assured of success, expand the source.  */
   start_sequence ();
-  pat = expand_expr (src, src_reg, Pmode, EXPAND_NORMAL);
+  rtx pat = expand_expr (src, src_reg, Pmode, EXPAND_NORMAL);
   if (pat != src_reg)
     {
 #ifdef POINTERS_EXTEND_UNSIGNED
@@ -3108,13 +3223,12 @@ expand_builtin_strnlen (tree exp, rtx target, machine_mode target_mode)
   if (!bound)
     return NULL_RTX;
 
+  check_read_access (exp, src, bound);
+
   location_t loc = UNKNOWN_LOCATION;
   if (EXPR_HAS_LOCATION (exp))
     loc = EXPR_LOCATION (exp);
 
-  tree maxobjsize = max_object_size ();
-  tree func = get_callee_fndecl (exp);
-
   /* FIXME: Change c_strlen() to return sizetype instead of ssizetype
      so these conversions aren't necessary.  */
   c_strlen_data lendata = { };
@@ -3124,48 +3238,6 @@ expand_builtin_strnlen (tree exp, rtx target, machine_mode target_mode)
 
   if (TREE_CODE (bound) == INTEGER_CST)
     {
-      if (!TREE_NO_WARNING (exp)
-         && tree_int_cst_lt (maxobjsize, bound)
-         && warning_at (loc, OPT_Wstringop_overflow_,
-                        "%K%qD specified bound %E "
-                        "exceeds maximum object size %E",
-                        exp, func, bound, maxobjsize))
-       TREE_NO_WARNING (exp) = true;
-
-      bool exact = true;
-      if (!len || TREE_CODE (len) != INTEGER_CST)
-       {
-         /* Clear EXACT if LEN may be less than SRC suggests,
-            such as in
-              strnlen (&a[i], sizeof a)
-            where the value of i is unknown.  Unless i's value is
-            zero, the call is unsafe because the bound is greater. */
-         lendata.decl = unterminated_array (src, &len, &exact);
-         if (!lendata.decl)
-           return NULL_RTX;
-       }
-
-      if (lendata.decl && (tree_int_cst_lt (len, bound) || !exact))
-       {
-         location_t warnloc
-           = expansion_point_location_if_in_system_header (loc);
-
-         if (!TREE_NO_WARNING (exp)
-             && warning_at (warnloc, OPT_Wstringop_overflow_,
-                            exact
-                            ? G_("%K%qD specified bound %E exceeds the size "
-                                 "%E of unterminated array")
-                            : G_("%K%qD specified bound %E may exceed the "
-                                 "size of at most %E of unterminated array"),
-                            exp, func, bound, len))
-           {
-             inform (DECL_SOURCE_LOCATION (lendata.decl),
-                     "referenced argument declared here");
-             TREE_NO_WARNING (exp) = true;
-           }
-         return NULL_RTX;
-       }
-
       if (!len)
        return NULL_RTX;
 
@@ -3181,44 +3253,14 @@ expand_builtin_strnlen (tree exp, rtx target, machine_mode target_mode)
   if (rng != VR_RANGE)
     return NULL_RTX;
 
-  if (!TREE_NO_WARNING (exp)
-      && wi::ltu_p (wi::to_wide (maxobjsize, min.get_precision ()), min)
-      && warning_at (loc, OPT_Wstringop_overflow_,
-                    "%K%qD specified bound [%wu, %wu] "
-                    "exceeds maximum object size %E",
-                    exp, func, min.to_uhwi (), max.to_uhwi (), maxobjsize))
-    TREE_NO_WARNING (exp) = true;
-
-  bool exact = true;
   if (!len || TREE_CODE (len) != INTEGER_CST)
     {
+      bool exact;
       lendata.decl = unterminated_array (src, &len, &exact);
       if (!lendata.decl)
        return NULL_RTX;
     }
 
-  if (lendata.decl
-      && !TREE_NO_WARNING (exp)
-      && (wi::ltu_p (wi::to_wide (len), min)
-         || !exact))
-    {
-      location_t warnloc
-       = expansion_point_location_if_in_system_header (loc);
-
-      if (warning_at (warnloc, OPT_Wstringop_overflow_,
-                     exact
-                     ? G_("%K%qD specified bound [%wu, %wu] exceeds "
-                          "the size %E of unterminated array")
-                     : G_("%K%qD specified bound [%wu, %wu] may exceed "
-                          "the size of at most %E of unterminated array"),
-                     exp, func, min.to_uhwi (), max.to_uhwi (), len))
-       {
-         inform (DECL_SOURCE_LOCATION (lendata.decl),
-                 "referenced argument declared here");
-         TREE_NO_WARNING (exp) = true;
-       }
-    }
-
   if (lendata.decl)
     return NULL_RTX;
 
@@ -3305,11 +3347,148 @@ determine_block_size (tree len, rtx len_rtx,
                          GET_MODE_MASK (GET_MODE (len_rtx)));
 }
 
+/* Issue a warning OPT for a bounded call EXP with a bound in RANGE
+   accessing an object with SIZE.  */
+
+static bool
+maybe_warn_for_bound (int opt, location_t loc, tree exp, tree func,
+                     tree bndrng[2], tree size, const access_data *pad = NULL)
+{
+  if (!bndrng[0] || TREE_NO_WARNING (exp))
+    return false;
+
+  tree maxobjsize = max_object_size ();
+
+  bool warned = false;
+
+  if (opt == OPT_Wstringop_overread)
+    {
+      if (tree_int_cst_lt (maxobjsize, bndrng[0]))
+       {
+         if (bndrng[0] == bndrng[1])
+           warned = (func
+                     ? warning_at (loc, opt,
+                                   "%K%qD specified bound %E "
+                                   "exceeds maximum object size %E",
+                                   exp, func, bndrng[0], maxobjsize)
+                     : warning_at (loc, opt,
+                                   "%Kspecified bound %E "
+                                   "exceeds maximum object size %E",
+                                   exp, bndrng[0], maxobjsize));
+         else
+           warned = (func
+                     ? warning_at (loc, opt,
+                                   "%K%qD specified bound [%E, %E] "
+                                   "exceeds maximum object size %E",
+                                   exp, func,
+                                   bndrng[0], bndrng[1], maxobjsize)
+                     : warning_at (loc, opt,
+                                   "%Kspecified bound [%E, %E] "
+                                   "exceeds maximum object size %E",
+                                   exp, bndrng[0], bndrng[1], maxobjsize));
+       }
+      else if (!size || tree_int_cst_le (bndrng[0], size))
+       return false;
+      else if (tree_int_cst_equal (bndrng[0], bndrng[1]))
+       warned = (func
+                 ? warning_at (loc, opt,
+                               "%K%qD specified bound %E exceeds "
+                               "source size %E",
+                               exp, func, bndrng[0], size)
+                 : warning_at (loc, opt,
+                               "%Kspecified bound %E exceeds "
+                               "source size %E",
+                               exp, bndrng[0], size));
+      else
+       warned = (func
+                 ? warning_at (loc, opt,
+                               "%K%qD specified bound [%E, %E] exceeds "
+                               "source size %E",
+                               exp, func, bndrng[0], bndrng[1], size)
+                 : warning_at (loc, opt,
+                               "%Kspecified bound [%E, %E] exceeds "
+                               "source size %E",
+                               exp, bndrng[0], bndrng[1], size));
+      if (warned)
+       {
+         if (pad && pad->src.ref)
+           {
+             if (DECL_P (pad->src.ref))
+               inform (DECL_SOURCE_LOCATION (pad->src.ref),
+                       "source object declared here");
+             else if (EXPR_HAS_LOCATION (pad->src.ref))
+               inform (EXPR_LOCATION (pad->src.ref),
+                       "source object allocated here");
+           }
+         TREE_NO_WARNING (exp) = true;
+       }
+
+      return warned;
+    }
+
+  if (tree_int_cst_lt (maxobjsize, bndrng[0]))
+    {
+      if (bndrng[0] == bndrng[1])
+       warned = (func
+                 ? warning_at (loc, opt,
+                               "%K%qD specified size %E "
+                               "exceeds maximum object size %E",
+                               exp, func, bndrng[0], maxobjsize)
+                 : warning_at (loc, opt,
+                               "%Kspecified size %E "
+                               "exceeds maximum object size %E",
+                               exp, bndrng[0], maxobjsize));
+      else
+       warned = (func
+                 ? warning_at (loc, opt,
+                               "%K%qD specified size between %E and %E "
+                               "exceeds maximum object size %E",
+                               exp, func,
+                               bndrng[0], bndrng[1], maxobjsize)
+                 : warning_at (loc, opt,
+                               "%Kspecified size between %E and %E "
+                               "exceeds maximum object size %E",
+                               exp, bndrng[0], bndrng[1], maxobjsize));
+    }
+  else if (!size || tree_int_cst_le (bndrng[0], size))
+    return false;
+  else if (tree_int_cst_equal (bndrng[0], bndrng[1]))
+    warned = (func
+             ? warning_at (loc, OPT_Wstringop_overflow_,
+                           "%K%qD specified bound %E exceeds "
+                           "destination size %E",
+                           exp, func, bndrng[0], size)
+             : warning_at (loc, OPT_Wstringop_overflow_,
+                           "%Kspecified bound %E exceeds "
+                           "destination size %E",
+                           exp, bndrng[0], size));
+  else
+    warned = (func
+             ? warning_at (loc, OPT_Wstringop_overflow_,
+                           "%K%qD specified bound [%E, %E] exceeds "
+                           "destination size %E",
+                           exp, func, bndrng[0], bndrng[1], size)
+             : warning_at (loc, OPT_Wstringop_overflow_,
+                           "%Kspecified bound [%E, %E] exceeds "
+                           "destination size %E",
+                           exp, bndrng[0], bndrng[1], size));
+
+  if (warned)
+    {
+      if (pad && pad->dst.ref)
+       inform (DECL_SOURCE_LOCATION (pad->dst.ref),
+               "destination object declared here");
+      TREE_NO_WARNING (exp) = true;
+    }
+
+  return warned;
+}
+
 /* For an expression EXP issue an access warning controlled by option OPT
    with access to a region SLEN bytes in size in the RANGE of sizes.  */
 
 static bool
-warn_for_access (location_t loc, tree func, tree exp, int opt, tree range[2],
+warn_for_access (location_t loc, tree func, tree exp, tree range[2],
                 tree slen, bool access)
 {
   bool warned = false;
@@ -3318,11 +3497,13 @@ warn_for_access (location_t loc, tree func, tree exp, int opt, tree range[2],
     {
       if (tree_int_cst_equal (range[0], range[1]))
        warned = (func
-                 ? warning_n (loc, opt, tree_to_uhwi (range[0]),
+                 ? warning_n (loc, OPT_Wstringop_overread,
+                              tree_to_uhwi (range[0]),
                               "%K%qD reading %E byte from a region of size %E",
                               "%K%qD reading %E bytes from a region of size %E",
                               exp, func, range[0], slen)
-                 : warning_n (loc, opt, tree_to_uhwi (range[0]),
+                 : warning_n (loc, OPT_Wstringop_overread,
+                              tree_to_uhwi (range[0]),
                               "%Kreading %E byte from a region of size %E",
                               "%Kreading %E bytes from a region of size %E",
                               exp, range[0], slen));
@@ -3330,36 +3511,41 @@ warn_for_access (location_t loc, tree func, tree exp, int opt, tree range[2],
        {
          /* Avoid printing the upper bound if it's invalid.  */
          warned = (func
-                   ? warning_at (loc, opt,
+                   ? warning_at (loc, OPT_Wstringop_overread,
                                  "%K%qD reading %E or more bytes from a region "
                                  "of size %E",
                                  exp, func, range[0], slen)
-                   : warning_at (loc, opt,
+                   : warning_at (loc, OPT_Wstringop_overread,
                                  "%Kreading %E or more bytes from a region "
                                  "of size %E",
                                  exp, range[0], slen));
        }
       else
        warned = (func
-                 ? warning_at (loc, opt,
+                 ? warning_at (loc, OPT_Wstringop_overread,
                                "%K%qD reading between %E and %E bytes from "
                                "a region of size %E",
                                exp, func, range[0], range[1], slen)
-                 : warning_at (loc, opt,
+                 : warning_at (loc, OPT_Wstringop_overread,
                                "%Kreading between %E and %E bytes from "
                                "a region of size %E",
                                exp, range[0], range[1], slen));
 
+      if (warned)
+       TREE_NO_WARNING (exp) = true;
+
       return warned;
     }
 
   if (tree_int_cst_equal (range[0], range[1]))
     warned = (func
-             ? warning_n (loc, opt, tree_to_uhwi (range[0]),
+             ? warning_n (loc, OPT_Wstringop_overread,
+                          tree_to_uhwi (range[0]),
                           "%K%qD epecting %E byte in a region of size %E",
                           "%K%qD expecting %E bytes in a region of size %E",
                           exp, func, range[0], slen)
-             : warning_n (loc, opt, tree_to_uhwi (range[0]),
+             : warning_n (loc, OPT_Wstringop_overread,
+                          tree_to_uhwi (range[0]),
                           "%Kexpecting %E byte in a region of size %E",
                           "%Kexpecting %E bytes in a region of size %E",
                           exp, range[0], slen));
@@ -3367,25 +3553,29 @@ warn_for_access (location_t loc, tree func, tree exp, int opt, tree range[2],
     {
       /* Avoid printing the upper bound if it's invalid.  */
       warned = (func
-               ? warning_at (loc, opt,
+               ? warning_at (loc, OPT_Wstringop_overread,
                              "%K%qD expecting %E or more bytes in a region "
                              "of size %E",
                              exp, func, range[0], slen)
-               : warning_at (loc, opt,
+               : warning_at (loc, OPT_Wstringop_overread,
                              "%Kexpecting %E or more bytes in a region "
                              "of size %E",
                              exp, range[0], slen));
     }
   else
     warned = (func
-             ? warning_at (loc, opt,
+             ? warning_at (loc, OPT_Wstringop_overread,
                            "%K%qD expecting between %E and %E bytes in "
                            "a region of size %E",
                            exp, func, range[0], range[1], slen)
-             : warning_at (loc, opt,
+             : warning_at (loc, OPT_Wstringop_overread,
                            "%Kexpectting between %E and %E bytes in "
                            "a region of size %E",
                            exp, range[0], range[1], slen));
+
+  if (warned)
+    TREE_NO_WARNING (exp) = true;
+
   return warned;
 }
 
@@ -3393,7 +3583,7 @@ warn_for_access (location_t loc, tree func, tree exp, int opt, tree range[2],
    WRITE is set for a write access and clear for a read access.  */
 
 static void
-inform_access (const access_ref &ref, bool write)
+inform_access (const access_ref &ref, access_mode mode)
 {
   if (!ref.ref)
     return;
@@ -3443,7 +3633,7 @@ inform_access (const access_ref &ref, bool write)
   else
     loc = DECL_SOURCE_LOCATION (ref.ref);
 
-  if (write)
+  if (mode == access_read_write || mode == access_write_only)
     {
       if (DECL_P (ref.ref))
        {
@@ -3513,6 +3703,34 @@ inform_access (const access_ref &ref, bool write)
            minoff, maxoff, sizestr, allocfn);
 }
 
+/* Helper to set RANGE to the range of BOUND if it's nonnull, bounded
+   by BNDRNG if nonnull and valid.  */
+
+static void
+get_size_range (tree bound, tree range[2], const offset_int bndrng[2])
+{
+  if (bound)
+    get_size_range (bound, range);
+
+  if (!bndrng || (bndrng[0] == 0 && bndrng[1] == HOST_WIDE_INT_M1U))
+    return;
+
+  if (range[0] && TREE_CODE (range[0]) == INTEGER_CST)
+    {
+      offset_int r[] =
+       { wi::to_offset (range[0]), wi::to_offset (range[1]) };
+      if (r[0] < bndrng[0])
+       range[0] = wide_int_to_tree (sizetype, bndrng[0]);
+      if (bndrng[1] < r[1])
+       range[1] = wide_int_to_tree (sizetype, bndrng[1]);
+    }
+  else
+    {
+      range[0] = wide_int_to_tree (sizetype, bndrng[0]);
+      range[1] = wide_int_to_tree (sizetype, bndrng[1]);
+    }
+}
+
 /* Try to verify that the sizes and lengths of the arguments to a string
    manipulation function given by EXP are within valid bounds and that
    the operation does not lead to buffer overflow or read past the end.
@@ -3531,10 +3749,7 @@ inform_access (const access_ref &ref, bool write)
    like memcpy).  As an exception, SRCSTR can also be an integer denoting
    the precomputed size of the source string or object (for functions like
    memcpy).
-   DSTSIZE is the size of the destination object specified by the last
-   argument to the _chk builtins, typically resulting from the expansion
-   of __builtin_object_size (such as in __builtin___strcpy_chk(DST, SRC,
-   DSTSIZE).
+   DSTSIZE is the size of the destination object.
 
    When DSTWRITE is null LEN is checked to verify that it doesn't exceed
    SIZE_MAX.
@@ -3548,21 +3763,22 @@ inform_access (const access_ref &ref, bool write)
    return false.  */
 
 bool
-check_access (tree exp, tree, tree, tree dstwrite,
+check_access (tree exp, tree dstwrite,
              tree maxread, tree srcstr, tree dstsize,
-             bool access /* = true */,
-             const access_data *pad /* = NULL */)
+             access_mode mode, const access_data *pad /* = NULL */)
 {
-  int opt = OPT_Wstringop_overflow_;
-
   /* The size of the largest object is half the address space, or
      PTRDIFF_MAX.  (This is way too permissive.)  */
   tree maxobjsize = max_object_size ();
 
-  /* Either the length of the source string for string functions or
-     the size of the source object for raw memory functions.  */
+  /* Either an approximate/minimum the length of the source string for
+     string functions or the size of the source object for raw memory
+     functions.  */
   tree slen = NULL_TREE;
 
+  /* The range of the access in bytes; first set to the write access
+     for functions that write and then read for those that also (or
+     just) read.  */
   tree range[2] = { NULL_TREE, NULL_TREE };
 
   /* Set to true when the exact number of bytes written by a string
@@ -3575,6 +3791,8 @@ check_access (tree exp, tree, tree, tree dstwrite,
         it can be an integer denoting the length of a string.  */
       if (POINTER_TYPE_P (TREE_TYPE (srcstr)))
        {
+         if (!check_nul_terminated_array (exp, srcstr, maxread))
+           return false;
          /* Try to determine the range of lengths the source string
             refers to.  If it can be determined and is less than
             the upper bound given by MAXREAD add one to it for
@@ -3584,7 +3802,10 @@ check_access (tree exp, tree, tree, tree dstwrite,
          get_range_strlen (srcstr, &lendata, /* eltsize = */ 1);
          range[0] = lendata.minlen;
          range[1] = lendata.maxbound ? lendata.maxbound : lendata.maxlen;
-         if (range[0] && (!maxread || TREE_CODE (maxread) == INTEGER_CST))
+         if (range[0]
+             && TREE_CODE (range[0]) == INTEGER_CST
+             && TREE_CODE (range[1]) == INTEGER_CST
+             && (!maxread || TREE_CODE (maxread) == INTEGER_CST))
            {
              if (maxread && tree_int_cst_le (maxread, range[0]))
                range[0] = range[1] = maxread;
@@ -3626,8 +3847,9 @@ check_access (tree exp, tree, tree, tree dstwrite,
   if (!dstsize)
     dstsize = maxobjsize;
 
-  if (dstwrite)
-    get_size_range (dstwrite, range);
+  /* Set RANGE to that of DSTWRITE if non-null, bounded by PAD->DST.BNDRNG
+     if valid.  */
+  get_size_range (dstwrite, range, pad ? pad->dst.bndrng : NULL);
 
   tree func = get_callee_fndecl (exp);
 
@@ -3637,37 +3859,11 @@ check_access (tree exp, tree, tree, tree dstwrite,
       && TREE_CODE (range[0]) == INTEGER_CST
       && tree_int_cst_lt (maxobjsize, range[0]))
     {
-      if (TREE_NO_WARNING (exp))
-       return false;
-
       location_t loc = tree_nonartificial_location (exp);
       loc = expansion_point_location_if_in_system_header (loc);
 
-      bool warned;
-      if (range[0] == range[1])
-       warned = (func
-                 ? warning_at (loc, opt,
-                               "%K%qD specified size %E "
-                               "exceeds maximum object size %E",
-                               exp, func, range[0], maxobjsize)
-                 : warning_at (loc, opt,
-                               "%Kspecified size %E "
-                               "exceeds maximum object size %E",
-                               exp, range[0], maxobjsize));
-      else
-       warned = (func
-                 ? warning_at (loc, opt,
-                               "%K%qD specified size between %E and %E "
-                               "exceeds maximum object size %E",
-                               exp, func,
-                               range[0], range[1], maxobjsize)
-                 : warning_at (loc, opt,
-                               "%Kspecified size between %E and %E "
-                               "exceeds maximum object size %E",
-                               exp, range[0], range[1], maxobjsize));
-      if (warned)
-       TREE_NO_WARNING (exp) = true;
-
+      maybe_warn_for_bound (OPT_Wstringop_overflow_, loc, exp, func, range,
+                           NULL_TREE, pad);
       return false;
     }
 
@@ -3687,7 +3883,8 @@ check_access (tree exp, tree, tree, tree dstwrite,
                  && tree_fits_uhwi_p (dstwrite)
                  && tree_int_cst_lt (dstwrite, range[0]))))
        {
-         if (TREE_NO_WARNING (exp))
+         if (TREE_NO_WARNING (exp)
+             || (pad && pad->dst.ref && TREE_NO_WARNING (pad->dst.ref)))
            return false;
 
          location_t loc = tree_nonartificial_location (exp);
@@ -3700,12 +3897,12 @@ check_access (tree exp, tree, tree, tree dstwrite,
                 and a source of unknown length.  The call will write
                 at least one byte past the end of the destination.  */
              warned = (func
-                       ? warning_at (loc, opt,
+                       ? warning_at (loc, OPT_Wstringop_overflow_,
                                      "%K%qD writing %E or more bytes into "
                                      "a region of size %E overflows "
                                      "the destination",
                                      exp, func, range[0], dstsize)
-                       : warning_at (loc, opt,
+                       : warning_at (loc, OPT_Wstringop_overflow_,
                                      "%Kwriting %E or more bytes into "
                                      "a region of size %E overflows "
                                      "the destination",
@@ -3713,13 +3910,15 @@ check_access (tree exp, tree, tree, tree dstwrite,
            }
          else if (tree_int_cst_equal (range[0], range[1]))
            warned = (func
-                     ? warning_n (loc, opt, tree_to_uhwi (range[0]),
+                     ? warning_n (loc, OPT_Wstringop_overflow_,
+                                  tree_to_uhwi (range[0]),
                                   "%K%qD writing %E byte into a region "
                                   "of size %E overflows the destination",
                                   "%K%qD writing %E bytes into a region "
                                   "of size %E overflows the destination",
                                   exp, func, range[0], dstsize)
-                     : warning_n (loc, opt, tree_to_uhwi (range[0]),
+                     : warning_n (loc, OPT_Wstringop_overflow_,
+                                  tree_to_uhwi (range[0]),
                                   "%Kwriting %E byte into a region "
                                   "of size %E overflows the destination",
                                   "%Kwriting %E bytes into a region "
@@ -3729,12 +3928,12 @@ check_access (tree exp, tree, tree, tree dstwrite,
            {
              /* Avoid printing the upper bound if it's invalid.  */
              warned = (func
-                       ? warning_at (loc, opt,
+                       ? warning_at (loc, OPT_Wstringop_overflow_,
                                      "%K%qD writing %E or more bytes into "
                                      "a region of size %E overflows "
                                      "the destination",
                                      exp, func, range[0], dstsize)
-                       : warning_at (loc, opt,
+                       : warning_at (loc, OPT_Wstringop_overflow_,
                                      "%Kwriting %E or more bytes into "
                                      "a region of size %E overflows "
                                      "the destination",
@@ -3742,13 +3941,13 @@ check_access (tree exp, tree, tree, tree dstwrite,
            }
          else
            warned = (func
-                     ? warning_at (loc, opt,
+                     ? warning_at (loc, OPT_Wstringop_overflow_,
                                    "%K%qD writing between %E and %E bytes "
                                    "into a region of size %E overflows "
                                    "the destination",
                                    exp, func, range[0], range[1],
                                    dstsize)
-                     : warning_at (loc, opt,
+                     : warning_at (loc, OPT_Wstringop_overflow_,
                                    "%Kwriting between %E and %E bytes "
                                    "into a region of size %E overflows "
                                    "the destination",
@@ -3758,7 +3957,7 @@ check_access (tree exp, tree, tree, tree dstwrite,
            {
              TREE_NO_WARNING (exp) = true;
              if (pad)
-               inform_access (pad->dst, true);
+               inform_access (pad->dst, pad->mode);
            }
 
          /* Return error when an overflow has been detected.  */
@@ -3771,113 +3970,95 @@ check_access (tree exp, tree, tree, tree dstwrite,
      of an object.  */
   if (maxread)
     {
-      get_size_range (maxread, range);
-      if (range[0] && dstsize && tree_fits_uhwi_p (dstsize))
-       {
-         location_t loc = tree_nonartificial_location (exp);
-         loc = expansion_point_location_if_in_system_header (loc);
+      /* Set RANGE to that of MAXREAD, bounded by PAD->SRC.BNDRNG if
+        PAD is nonnull and BNDRNG is valid.  */
+      get_size_range (maxread, range, pad ? pad->src.bndrng : NULL);
+
+      location_t loc = tree_nonartificial_location (exp);
+      loc = expansion_point_location_if_in_system_header (loc);
 
+      tree size = dstsize;
+      if (pad && pad->mode == access_read_only)
+       size = wide_int_to_tree (sizetype, pad->src.sizrng[1]);
+
+      if (range[0] && maxread && tree_fits_uhwi_p (size))
+       {
          if (tree_int_cst_lt (maxobjsize, range[0]))
            {
-             if (TREE_NO_WARNING (exp))
-               return false;
-
-             bool warned = false;
-
-             /* Warn about crazy big sizes first since that's more
-                likely to be meaningful than saying that the bound
-                is greater than the object size if both are big.  */
-             if (range[0] == range[1])
-               warned = (func
-                         ? warning_at (loc, opt,
-                                       "%K%qD specified bound %E "
-                                       "exceeds maximum object size %E",
-                                       exp, func, range[0], maxobjsize)
-                         : warning_at (loc, opt,
-                                       "%Kspecified bound %E "
-                                       "exceeds maximum object size %E",
-                                       exp, range[0], maxobjsize));
-             else
-               warned = (func
-                         ? warning_at (loc, opt,
-                                       "%K%qD specified bound between "
-                                       "%E and %E exceeds maximum object "
-                                       "size %E",
-                                       exp, func,
-                                       range[0], range[1], maxobjsize)
-                         : warning_at (loc, opt,
-                                       "%Kspecified bound between "
-                                       "%E and %E exceeds maximum object "
-                                       "size %E",
-                                       exp, range[0], range[1], maxobjsize));
-             if (warned)
-               TREE_NO_WARNING (exp) = true;
-
+             maybe_warn_for_bound (OPT_Wstringop_overread, loc, exp, func,
+                                   range, size, pad);
              return false;
            }
 
-         if (dstsize != maxobjsize && tree_int_cst_lt (dstsize, range[0]))
+         if (size != maxobjsize && tree_int_cst_lt (size, range[0]))
            {
-             if (TREE_NO_WARNING (exp))
-               return false;
-
-             bool warned = false;
-
-             if (tree_int_cst_equal (range[0], range[1]))
-               warned = (func
-                         ? warning_at (loc, opt,
-                                       "%K%qD specified bound %E "
-                                       "exceeds destination size %E",
-                                       exp, func,
-                                       range[0], dstsize)
-                         : warning_at (loc, opt,
-                                       "%Kspecified bound %E "
-                                       "exceeds destination size %E",
-                                       exp, range[0], dstsize));
-             else
-               warned = (func
-                         ? warning_at (loc, opt,
-                                       "%K%qD specified bound between %E "
-                                       "and %E exceeds destination size %E",
-                                       exp, func,
-                                       range[0], range[1], dstsize)
-                         : warning_at (loc, opt,
-                                       "%Kspecified bound between %E "
-                                       "and %E exceeds destination size %E",
-                                       exp,
-                                       range[0], range[1], dstsize));
-             if (warned)
-               TREE_NO_WARNING (exp) = true;
-
+             int opt = (dstwrite || mode != access_read_only
+                        ? OPT_Wstringop_overflow_
+                        : OPT_Wstringop_overread);
+             maybe_warn_for_bound (opt, loc, exp, func, range, size, pad);
              return false;
            }
        }
+
+      maybe_warn_nonstring_arg (func, exp);
     }
 
   /* Check for reading past the end of SRC.  */
-  if (slen
-      && slen == srcstr
-      && dstwrite && range[0]
-      && tree_int_cst_lt (slen, range[0]))
+  bool overread = (slen
+                  && slen == srcstr
+                  && dstwrite
+                  && range[0]
+                  && TREE_CODE (slen) == INTEGER_CST
+                  && tree_int_cst_lt (slen, range[0]));
+
+  if (!overread && pad && pad->src.sizrng[1] >= 0 && pad->src.offrng[0] >= 0)
     {
-      if (TREE_NO_WARNING (exp))
+      /* Set RANGE to that of MAXREAD, bounded by PAD->SRC.BNDRNG if
+        PAD is nonnull and BNDRNG is valid.  */
+      get_size_range (maxread, range, pad ? pad->src.bndrng : NULL);
+      /* Set OVERREAD for reads starting just past the end of an object.  */
+      overread = pad->src.sizrng[1] - pad->src.offrng[0] < pad->src.bndrng[0];
+      range[0] = wide_int_to_tree (sizetype, pad->src.bndrng[0]);
+      slen = size_zero_node;
+    }
+
+  if (overread)
+    {
+      if (TREE_NO_WARNING (exp)
+         || (srcstr && TREE_NO_WARNING (srcstr))
+         || (pad && pad->src.ref && TREE_NO_WARNING (pad->src.ref)))
        return false;
 
       location_t loc = tree_nonartificial_location (exp);
       loc = expansion_point_location_if_in_system_header (loc);
 
-      if (warn_for_access (loc, func, exp, opt, range, slen, access))
-       {
-         TREE_NO_WARNING (exp) = true;
-         if (pad)
-           inform_access (pad->src, false);
-       }
+      if (warn_for_access (loc, func, exp, range, slen, mode)
+         && pad)
+       inform_access (pad->src, access_read_only);
+
       return false;
     }
 
   return true;
 }
 
+/* A convenience wrapper for check_access above to check access
+   by a read-only function like puts.  */
+
+static bool
+check_read_access (tree exp, tree src, tree bound /* = NULL_TREE */,
+                  int ost /* = 1 */)
+{
+  if (!warn_stringop_overread)
+    return true;
+
+  access_data data (exp, access_read_only, NULL_TREE, false, bound, true);
+  compute_objsize (src, ost, &data.src);
+  return check_access (exp, /*dstwrite=*/ NULL_TREE, /*maxread=*/ bound,
+                      /*srcstr=*/ src, /*dstsize=*/ NULL_TREE, data.mode,
+                      &data);
+}
+
 /* If STMT is a call to an allocation function, returns the constant
    size of the object allocated by the call represented as sizetype.
    If nonnull, sets RNG1[] to the range of the size.  */
@@ -4216,7 +4397,7 @@ compute_objsize (tree ptr, int ostype, access_ref *pref,
 
 static tree
 compute_objsize (tree ptr, int ostype, access_ref *pref,
-                const vr_values *rvals = NULL)
+                const vr_values *rvals /* = NULL */)
 {
   bitmap visited = NULL;
 
@@ -4280,12 +4461,12 @@ check_memop_access (tree exp, tree dest, tree src, tree size)
      try to determine the size of the largest source and destination
      object using type-0 Object Size regardless of the object size
      type specified by the option.  */
-  access_data data;
+  access_data data (exp, access_read_write);
   tree srcsize = src ? compute_objsize (src, 0, &data.src) : NULL_TREE;
   tree dstsize = compute_objsize (dest, 0, &data.dst);
 
-  return check_access (exp, dest, src, size, /*maxread=*/NULL_TREE,
-                      srcsize, dstsize, true, &data);
+  return check_access (exp, size, /*maxread=*/NULL_TREE,
+                      srcsize, dstsize, data.mode, &data);
 }
 
 /* Validate memchr arguments without performing any expansion.
@@ -4301,16 +4482,7 @@ expand_builtin_memchr (tree exp, rtx)
   tree arg1 = CALL_EXPR_ARG (exp, 0);
   tree len = CALL_EXPR_ARG (exp, 2);
 
-  /* Diagnose calls where the specified length exceeds the size
-     of the object.  */
-  if (warn_stringop_overflow)
-    {
-      access_data data;
-      tree size = compute_objsize (arg1, 0, &data.src);
-      check_access (exp, /*dst=*/NULL_TREE, /*src=*/NULL_TREE, len,
-                   /*maxread=*/NULL_TREE, size, /*objsize=*/NULL_TREE,
-                   true, &data);
-    }
+  check_read_access (exp, arg1, len, 0);
 
   return NULL_RTX;
 }
@@ -4580,20 +4752,18 @@ expand_builtin_strcat (tree exp)
   tree dest = CALL_EXPR_ARG (exp, 0);
   tree src = CALL_EXPR_ARG (exp, 1);
 
-  /* Detect unterminated source (only).  */
-  if (!check_nul_terminated_array (exp, src))
-    return NULL_RTX;
-
   /* There is no way here to determine the length of the string in
      the destination to which the SRC string is being appended so
      just diagnose cases when the souce string is longer than
      the destination object.  */
+  access_data data (exp, access_read_write, NULL_TREE, true,
+                   NULL_TREE, true);
+  const int ost = warn_stringop_overflow ? warn_stringop_overflow - 1 : 1;
+  compute_objsize (src, ost, &data.src);
+  tree destsize = compute_objsize (dest, ost, &data.dst);
 
-  access_data data;
-  tree destsize = compute_objsize (dest, warn_stringop_overflow - 1, &data.dst);
-
-  check_access (exp, dest, src, /*size=*/NULL_TREE, /*maxread=*/NULL_TREE, src,
-               destsize, true, &data);
+  check_access (exp, /*dstwrite=*/NULL_TREE, /*maxread=*/NULL_TREE,
+               src, destsize, data.mode, &data);
 
   return NULL_RTX;
 }
@@ -4614,11 +4784,14 @@ expand_builtin_strcpy (tree exp, rtx target)
 
   if (warn_stringop_overflow)
     {
-      access_data data;
-      tree destsize = compute_objsize (dest, warn_stringop_overflow - 1,
-                                      &data.dst);
-      check_access (exp, dest, src, /*size=*/NULL_TREE, /*maxread=*/NULL_TREE,
-                   src, destsize, true, &data);
+      access_data data (exp, access_read_write, NULL_TREE, true,
+                       NULL_TREE, true);
+      const int ost = warn_stringop_overflow ? warn_stringop_overflow - 1 : 1;
+      compute_objsize (src, ost, &data.src);
+      tree dstsize = compute_objsize (dest, ost, &data.dst);
+      check_access (exp, /*dstwrite=*/ NULL_TREE,
+                   /*maxread=*/ NULL_TREE, /*srcstr=*/ src,
+                   dstsize, data.mode, &data);
     }
 
   if (rtx ret = expand_builtin_strcpy_args (exp, dest, src, target))
@@ -4644,11 +4817,13 @@ static rtx
 expand_builtin_strcpy_args (tree exp, tree dest, tree src, rtx target)
 {
   /* Detect strcpy calls with unterminated arrays..  */
-  if (tree nonstr = unterminated_array (src))
+  tree size;
+  bool exact;
+  if (tree nonstr = unterminated_array (src, &size, &exact))
     {
       /* NONSTR refers to the non-nul terminated constant array.  */
-      if (!TREE_NO_WARNING (exp))
-       warn_string_no_nul (EXPR_LOCATION (exp), "strcpy", src, nonstr);
+      warn_string_no_nul (EXPR_LOCATION (exp), exp, NULL, src, nonstr,
+                         size, exact);
       return NULL_RTX;
     }
 
@@ -4674,11 +4849,11 @@ expand_builtin_stpcpy_1 (tree exp, rtx target, machine_mode mode)
 
   if (warn_stringop_overflow)
     {
-      access_data data;
+      access_data data (exp, access_read_write);
       tree destsize = compute_objsize (dst, warn_stringop_overflow - 1,
                                       &data.dst);
-      check_access (exp, dst, src, /*size=*/NULL_TREE, /*maxread=*/NULL_TREE,
-                   src, destsize, true, &data);
+      check_access (exp, /*dstwrite=*/NULL_TREE, /*maxread=*/NULL_TREE,
+                   src, destsize, data.mode, &data);
     }
 
   /* If return value is ignored, transform stpcpy into strcpy.  */
@@ -4703,8 +4878,8 @@ expand_builtin_stpcpy_1 (tree exp, rtx target, machine_mode mode)
        return expand_movstr (dst, src, target,
                              /*retmode=*/ RETURN_END_MINUS_ONE);
 
-      if (lendata.decl && !TREE_NO_WARNING (exp))
-       warn_string_no_nul (EXPR_LOCATION (exp), "stpcpy", src, lendata.decl);
+      if (lendata.decl)
+       warn_string_no_nul (EXPR_LOCATION (exp), exp, NULL, src, lendata.decl);
 
       lenp1 = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1));
       ret = expand_builtin_mempcpy_args (dst, src, lenp1,
@@ -4784,15 +4959,10 @@ expand_builtin_stpncpy (tree exp, rtx)
 
   /* The exact number of bytes to write (not the maximum).  */
   tree len = CALL_EXPR_ARG (exp, 2);
-  if (!check_nul_terminated_array (exp, src, len))
-    return NULL_RTX;
-
-  access_data data;
+  access_data data (exp, access_read_write);
   /* The size of the destination object.  */
   tree destsize = compute_objsize (dest, warn_stringop_overflow - 1, &data.dst);
-
-  check_access (exp, dest, src, len, /*maxread=*/NULL_TREE, src, destsize,
-               true, &data);
+  check_access (exp, len, /*maxread=*/len, src, destsize, data.mode, &data);
 
   return NULL_RTX;
 }
@@ -4832,7 +5002,7 @@ check_strncat_sizes (tree exp, tree objsize)
   /* Try to verify that the destination is big enough for the shortest
      string.  */
 
-  access_data data;
+  access_data data (exp, access_read_write, maxread, true);
   if (!objsize && warn_stringop_overflow)
     {
       /* If it hasn't been provided by __strncat_chk, try to determine
@@ -4871,8 +5041,8 @@ check_strncat_sizes (tree exp, tree objsize)
 
   /* The number of bytes to write is LEN but check_access will alsoa
      check SRCLEN if LEN's value isn't known.  */
-  return check_access (exp, dest, src, /*size=*/NULL_TREE, maxread, srclen,
-                      objsize, true, &data);
+  return check_access (exp, /*dstwrite=*/NULL_TREE, maxread, srclen,
+                      objsize, data.mode, &data);
 }
 
 /* Similar to expand_builtin_strcat, do some very basic size validation
@@ -4910,7 +5080,7 @@ expand_builtin_strncat (tree exp, rtx)
       maxlen = lendata.maxbound;
     }
 
-  access_data data;
+  access_data data (exp, access_read_write);
   /* Try to verify that the destination is big enough for the shortest
      string.  First try to determine the size of the destination object
      into which the source is being copied.  */
@@ -4944,8 +5114,8 @@ expand_builtin_strncat (tree exp, rtx)
          && tree_int_cst_lt (maxread, srclen)))
     srclen = maxread;
 
-  check_access (exp, dest, src, NULL_TREE, maxread, srclen, destsize,
-               true, &data);
+  check_access (exp, /*dstwrite=*/NULL_TREE, maxread, srclen,
+               destsize, data.mode, &data);
 
   return NULL_RTX;
 }
@@ -4966,22 +5136,19 @@ expand_builtin_strncpy (tree exp, rtx target)
   /* The number of bytes to write (not the maximum).  */
   tree len = CALL_EXPR_ARG (exp, 2);
 
-  if (!check_nul_terminated_array (exp, src, len))
-    return NULL_RTX;
-
   /* The length of the source sequence.  */
   tree slen = c_strlen (src, 1);
 
   if (warn_stringop_overflow)
     {
-      access_data data;
-      tree destsize = compute_objsize (dest, warn_stringop_overflow - 1,
-                                      &data.dst);
-
+      access_data data (exp, access_read_write, len, true, len, true);
+      const int ost = warn_stringop_overflow ? warn_stringop_overflow - 1 : 1;
+      compute_objsize (src, ost, &data.src);
+      tree dstsize = compute_objsize (dest, ost, &data.dst);
       /* The number of bytes to write is LEN but check_access will also
         check SLEN if LEN's value isn't known.  */
-      check_access (exp, dest, src, len, /*maxread=*/NULL_TREE, src,
-                   destsize, true, &data);
+      check_access (exp, /*dstwrite=*/len,
+                   /*maxread=*/len, src, dstsize, data.mode, &data);
     }
 
   /* We must be passed a constant len and src parameter.  */
@@ -5289,34 +5456,17 @@ expand_builtin_memcmp (tree exp, rtx target, bool result_eq)
   tree arg1 = CALL_EXPR_ARG (exp, 0);
   tree arg2 = CALL_EXPR_ARG (exp, 1);
   tree len = CALL_EXPR_ARG (exp, 2);
-  enum built_in_function fcode = DECL_FUNCTION_CODE (get_callee_fndecl (exp));
-  bool no_overflow = true;
 
   /* Diagnose calls where the specified length exceeds the size of either
      object.  */
-  access_data data;
-  tree size = compute_objsize (arg1, 0, &data.src);
-  no_overflow = check_access (exp, /*dst=*/NULL_TREE, /*src=*/NULL_TREE,
-                             len, /*maxread=*/NULL_TREE, size,
-                             /*objsize=*/NULL_TREE, true, &data);
-  if (no_overflow)
-    {
-      access_data data;
-      size = compute_objsize (arg2, 0, &data.src);
-      no_overflow = check_access (exp, /*dst=*/NULL_TREE, /*src=*/NULL_TREE,
-                                 len,  /*maxread=*/NULL_TREE, size,
-                                 /*objsize=*/NULL_TREE, true, &data);
-    }
-
-  /* If the specified length exceeds the size of either object, 
-     call the function.  */
-  if (!no_overflow)
+  if (!check_read_access (exp, arg1, len, 0)
+      || !check_read_access (exp, arg2, len, 0))
     return NULL_RTX;
 
   /* Due to the performance benefit, always inline the calls first
      when result_eq is false.  */
   rtx result = NULL_RTX;
-
+  enum built_in_function fcode = DECL_FUNCTION_CODE (get_callee_fndecl (exp));
   if (!result_eq && fcode != BUILT_IN_BCMP)
     {
       result = inline_expand_builtin_bytecmp (exp, target);
@@ -5405,8 +5555,8 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
   tree arg1 = CALL_EXPR_ARG (exp, 0);
   tree arg2 = CALL_EXPR_ARG (exp, 1);
 
-  if (!check_nul_terminated_array (exp, arg1)
-      || !check_nul_terminated_array (exp, arg2))
+  if (!check_read_access (exp, arg1)
+      || !check_read_access (exp, arg2))
     return NULL_RTX;
 
   /* Due to the performance benefit, always inline the calls first.  */
@@ -5514,8 +5664,8 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
 }
 
 /* Expand expression EXP, which is a call to the strncmp builtin. Return
-   NULL_RTX if we failed the caller should emit a normal call, otherwise try to get
-   the result in TARGET, if convenient.  */
+   NULL_RTX if we failed the caller should emit a normal call, otherwise
+   try to get the result in TARGET, if convenient.  */
 
 static rtx
 expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
@@ -5533,6 +5683,56 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
       || !check_nul_terminated_array (exp, arg2, arg3))
     return NULL_RTX;
 
+  location_t loc = tree_nonartificial_location (exp);
+  loc = expansion_point_location_if_in_system_header (loc);
+
+  tree len1 = c_strlen (arg1, 1);
+  tree len2 = c_strlen (arg2, 1);
+
+  if (!len1 || !len2)
+    {
+      /* Check to see if the argument was declared attribute nonstring
+        and if so, issue a warning since at this point it's not known
+        to be nul-terminated.  */
+      if (!maybe_warn_nonstring_arg (get_callee_fndecl (exp), exp)
+         && !len1 && !len2)
+       {
+         /* A strncmp read is constrained not just by the bound but
+            also by the length of the shorter string.  Specifying
+            a bound that's larger than the size of either array makes
+            no sense and is likely a bug.  When the length of neither
+            of the two strings is known but the sizes of both of
+            the arrays they are stored in is, issue a warning if
+            the bound is larger than than the size of the larger
+            of the two arrays.  */
+
+         access_ref ref1 (arg3, true);
+         access_ref ref2 (arg3, true);
+
+         tree bndrng[2] = { NULL_TREE, NULL_TREE };
+         get_size_range (arg3, bndrng, ref1.bndrng);
+
+         tree size1 = compute_objsize (arg1, 1, &ref1);
+         tree size2 = compute_objsize (arg2, 1, &ref2);
+         tree func = get_callee_fndecl (exp);
+
+         if (size1 && size2)
+           {
+             tree maxsize = tree_int_cst_le (size1, size2) ? size2 : size1;
+
+             if (tree_int_cst_lt (maxsize, bndrng[0]))
+               maybe_warn_for_bound (OPT_Wstringop_overread, loc, exp, func,
+                                     bndrng, maxsize);
+           }
+         else if (bndrng[0]
+                  && !integer_zerop (bndrng[0])
+                  && ((size1 && integer_zerop (size1))
+                      || (size2 && integer_zerop (size2))))
+           maybe_warn_for_bound (OPT_Wstringop_overread, loc, exp, func,
+                                 bndrng, integer_zero_node);
+       }
+    }
+
   /* Due to the performance benefit, always inline the calls first.  */
   rtx result = NULL_RTX;
   result = inline_expand_builtin_bytecmp (exp, target);
@@ -5551,11 +5751,6 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
   unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
   unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
 
-  tree len1 = c_strlen (arg1, 1);
-  tree len2 = c_strlen (arg2, 1);
-
-  location_t loc = EXPR_LOCATION (exp);
-
   if (len1)
     len1 = size_binop_loc (loc, PLUS_EXPR, ssize_int (1), len1);
   if (len2)
@@ -5607,11 +5802,6 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
   tree fndecl = get_callee_fndecl (exp);
   if (result)
     {
-      /* Check to see if the argument was declared attribute nonstring
-        and if so, issue a warning since at this point it's not known
-        to be nul-terminated.  */
-      maybe_warn_nonstring_arg (fndecl, exp);
-
       /* Return the value in the proper mode for this function.  */
       mode = TYPE_MODE (TREE_TYPE (exp));
       if (GET_MODE (result) == mode)
@@ -5624,10 +5814,12 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
 
   /* Expand the library call ourselves using a stabilized argument
      list to avoid re-evaluating the function's arguments twice.  */
-  tree fn = build_call_nofold_loc (loc, fndecl, 3, arg1, arg2, len);
-  gcc_assert (TREE_CODE (fn) == CALL_EXPR);
-  CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
-  return expand_call (fn, target, target == const0_rtx);
+  tree call = build_call_nofold_loc (loc, fndecl, 3, arg1, arg2, len);
+  if (TREE_NO_WARNING (exp))
+    TREE_NO_WARNING (call) = true;
+  gcc_assert (TREE_CODE (call) == CALL_EXPR);
+  CALL_EXPR_TAILCALL (call) = CALL_EXPR_TAILCALL (exp);
+  return expand_call (call, target, target == const0_rtx);
 }
 
 /* Expand a call to __builtin_saveregs, generating the result in TARGET,
@@ -6544,8 +6736,9 @@ expand_builtin_fork_or_exec (tree fn, tree exp, rtx target, int ignore)
 
   if (DECL_FUNCTION_CODE (fn) != BUILT_IN_FORK)
     {
+      tree path = CALL_EXPR_ARG (exp, 0);
       /* Detect unterminated path.  */
-      if (!check_nul_terminated_array (exp, CALL_EXPR_ARG (exp, 0)))
+      if (!check_read_access (exp, path))
        return NULL_RTX;
 
       /* Also detect unterminated first argument.  */
@@ -6554,7 +6747,7 @@ expand_builtin_fork_or_exec (tree fn, tree exp, rtx target, int ignore)
        case BUILT_IN_EXECL:
        case BUILT_IN_EXECLE:
        case BUILT_IN_EXECLP:
-         if (!check_nul_terminated_array (exp, CALL_EXPR_ARG (exp, 0)))
+         if (!check_read_access (exp, path))
            return NULL_RTX;
        default:
          break;
@@ -8262,7 +8455,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
     case BUILT_IN_PUTS_UNLOCKED:
     case BUILT_IN_STRDUP:
       if (validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
-       check_nul_terminated_array (exp, CALL_EXPR_ARG (exp, 0));
+       check_read_access (exp, CALL_EXPR_ARG (exp, 0));
       break;
 
     case BUILT_IN_INDEX:
@@ -8270,28 +8463,29 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
     case BUILT_IN_STRCHR:
     case BUILT_IN_STRRCHR:
       if (validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
-       check_nul_terminated_array (exp, CALL_EXPR_ARG (exp, 0));
+       check_read_access (exp, CALL_EXPR_ARG (exp, 0));
       break;
 
     case BUILT_IN_FPUTS:
     case BUILT_IN_FPUTS_UNLOCKED:
       if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
-       check_nul_terminated_array (exp, CALL_EXPR_ARG (exp, 0));
+       check_read_access (exp, CALL_EXPR_ARG (exp, 0));
       break;
 
     case BUILT_IN_STRNDUP:
       if (validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
-       check_nul_terminated_array (exp,
-                                   CALL_EXPR_ARG (exp, 0),
-                                   CALL_EXPR_ARG (exp, 1));
+       check_read_access (exp, CALL_EXPR_ARG (exp, 0), CALL_EXPR_ARG (exp, 1));
       break;
 
     case BUILT_IN_STRCASECMP:
+    case BUILT_IN_STRPBRK:
+    case BUILT_IN_STRSPN:
+    case BUILT_IN_STRCSPN:
     case BUILT_IN_STRSTR:
       if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
        {
-         check_nul_terminated_array (exp, CALL_EXPR_ARG (exp, 0));
-         check_nul_terminated_array (exp, CALL_EXPR_ARG (exp, 1));
+         check_read_access (exp, CALL_EXPR_ARG (exp, 0));
+         check_read_access (exp, CALL_EXPR_ARG (exp, 1));
        }
       break;
 
@@ -9321,10 +9515,11 @@ fold_builtin_classify_type (tree arg)
   return build_int_cst (integer_type_node, type_to_class (TREE_TYPE (arg)));
 }
 
-/* Fold a call to __builtin_strlen with argument ARG.  */
+/* Fold a call EXPR (which may be null) to __builtin_strlen with argument
+   ARG.  */
 
 static tree
-fold_builtin_strlen (location_t loc, tree type, tree arg)
+fold_builtin_strlen (location_t loc, tree expr, tree type, tree arg)
 {
   if (!validate_arg (arg, POINTER_TYPE))
     return NULL_TREE;
@@ -9345,7 +9540,7 @@ fold_builtin_strlen (location_t loc, tree type, tree arg)
            loc = EXPR_LOCATION (arg);
          else if (loc == UNKNOWN_LOCATION)
            loc = input_location;
-         warn_string_no_nul (loc, "strlen", arg, lendata.decl);
+         warn_string_no_nul (loc, expr, "strlen", arg, lendata.decl);
        }
 
       return NULL_TREE;
@@ -10234,7 +10429,7 @@ fold_builtin_0 (location_t loc, tree fndecl)
    This function returns NULL_TREE if no simplification was possible.  */
 
 static tree
-fold_builtin_1 (location_t loc, tree fndecl, tree arg0)
+fold_builtin_1 (location_t loc, tree expr, tree fndecl, tree arg0)
 {
   tree type = TREE_TYPE (TREE_TYPE (fndecl));
   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
@@ -10264,7 +10459,7 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0)
       return fold_builtin_classify_type (arg0);
 
     case BUILT_IN_STRLEN:
-      return fold_builtin_strlen (loc, type, arg0);
+      return fold_builtin_strlen (loc, expr, type, arg0);
 
     CASE_FLT_FN (BUILT_IN_FABS):
     CASE_FLT_FN_FLOATN_NX (BUILT_IN_FABS):
@@ -10531,7 +10726,7 @@ fold_builtin_n (location_t loc, tree expr, tree fndecl, tree *args,
       ret = fold_builtin_0 (loc, fndecl);
       break;
     case 1:
-      ret = fold_builtin_1 (loc, fndecl, args[0]);
+      ret = fold_builtin_1 (loc, expr, fndecl, args[0]);
       break;
     case 2:
       ret = fold_builtin_2 (loc, expr, fndecl, args[0], args[1]);
@@ -10822,16 +11017,12 @@ readonly_data_expr (tree exp)
    form of the builtin function call.  */
 
 static tree
-fold_builtin_strpbrk (location_t loc, tree expr, tree s1, tree s2, tree type)
+fold_builtin_strpbrk (location_t loc, tree, tree s1, tree s2, tree type)
 {
   if (!validate_arg (s1, POINTER_TYPE)
       || !validate_arg (s2, POINTER_TYPE))
     return NULL_TREE;
 
-  if (!check_nul_terminated_array (expr, s1)
-      || !check_nul_terminated_array (expr, s2))
-    return NULL_TREE;
-
   tree fn;
   const char *p1, *p2;
 
@@ -11134,8 +11325,9 @@ expand_builtin_memory_chk (tree exp, rtx target, machine_mode mode,
   tree len = CALL_EXPR_ARG (exp, 2);
   tree size = CALL_EXPR_ARG (exp, 3);
 
-  bool sizes_ok = check_access (exp, dest, src, len, /*maxread=*/NULL_TREE,
-                               /*str=*/NULL_TREE, size);
+  /* FIXME: Set access mode to write only for memset et al.  */
+  bool sizes_ok = check_access (exp, len, /*maxread=*/NULL_TREE,
+                               /*srcstr=*/NULL_TREE, size, access_read_write);
 
   if (!tree_fits_uhwi_p (size))
     return NULL_RTX;
@@ -11236,7 +11428,7 @@ maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
 {
   /* The source string.  */
   tree srcstr = NULL_TREE;
-  /* The size of the destination object.  */
+  /* The size of the destination object returned by __builtin_object_size.  */
   tree objsize = NULL_TREE;
   /* The string that is being concatenated with (as in __strcat_chk)
      or null if it isn't.  */
@@ -11247,6 +11439,9 @@ maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
   tree maxread = NULL_TREE;
   /* The exact size of the access (such as in __strncpy_chk).  */
   tree size = NULL_TREE;
+  /* The access by the function that's checked.  Except for snprintf
+     both writing and reading is checked.  */
+  access_mode mode = access_read_write;
 
   switch (fcode)
     {
@@ -11282,6 +11477,8 @@ maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
     case BUILT_IN_VSNPRINTF_CHK:
       maxread = CALL_EXPR_ARG (exp, 1);
       objsize = CALL_EXPR_ARG (exp, 3);
+      /* The only checked access the write to the destination.  */
+      mode = access_write_only;
       break;
     default:
       gcc_unreachable ();
@@ -11296,10 +11493,7 @@ maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
       return;
     }
 
-  /* The destination argument is the first one for all built-ins above.  */
-  tree dst = CALL_EXPR_ARG (exp, 0);
-
-  check_access (exp, dst, srcstr, size, maxread, srcstr, objsize);
+  check_access (exp, size, maxread, srcstr, objsize, mode);
 }
 
 /* Emit warning if a buffer overflow is detected at compile time
@@ -11356,8 +11550,8 @@ maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode)
   /* Add one for the terminating nul.  */
   len = fold_build2 (PLUS_EXPR, TREE_TYPE (len), len, size_one_node);
 
-  check_access (exp, /*dst=*/NULL_TREE, /*src=*/NULL_TREE, /*size=*/NULL_TREE,
-               /*maxread=*/NULL_TREE, len, size);
+  check_access (exp, /*size=*/NULL_TREE, /*maxread=*/NULL_TREE, len, size,
+               access_write_only);
 }
 
 /* Emit warning if a free is called with address of a variable.  */
index 8b812ceb2c4e9660519b12004b0ce4171a378562..94ff96b1292258b131b74eabdfc9d3cc3ef14e97 100644 (file)
@@ -153,38 +153,56 @@ extern internal_fn associated_internal_fn (tree);
 extern internal_fn replacement_internal_fn (gcall *);
 
 extern bool check_nul_terminated_array (tree, tree, tree = NULL_TREE);
-extern void warn_string_no_nul (location_t, const char *, tree, tree);
+extern void warn_string_no_nul (location_t, tree, const char *, tree,
+                               tree, tree = NULL_TREE, bool = false,
+                               const wide_int[2] = NULL);
 extern tree unterminated_array (tree, tree * = NULL, bool * = NULL);
 extern bool builtin_with_linkage_p (tree);
 
 /* Describes a reference to an object used in an access.  */
 struct access_ref
 {
-  access_ref (): ref ()
-  {
-    /* Set to valid.  */
-    offrng[0] = offrng[1] = 0;
-    /* Invalidate.   */
-    sizrng[0] = sizrng[1] = -1;
-  }
-
-  /* Reference to the object.  */
+  /* Set the bounds of the reference to at most as many bytes
+     as the first argument or unknown when null, and at least
+     one when the second argument is true unless the first one
+     is a constant zero.  */
+  access_ref (tree = NULL_TREE, bool = false);
+
+  /* Reference to the accessed object(s).  */
   tree ref;
 
-  /* Range of offsets into and sizes of the object(s).  */
+  /* Range of byte offsets into and sizes of the object(s).  */
   offset_int offrng[2];
   offset_int sizrng[2];
+  /* Range of the bound of the access: denotes that the access
+     is at least BNDRNG[0] bytes but no more than BNDRNG[1].
+     For string functions the size of the actual access is
+     further constrained by the length of the string.  */
+  offset_int bndrng[2];
 };
 
 /* Describes a pair of references used in an access by built-in
    functions like memcpy.  */
 struct access_data
 {
+  /* Set the access to at most MAXWRITE and MAXREAD bytes, and
+     at least 1 when MINWRITE or MINREAD, respectively, is set.  */
+  access_data (tree expr, access_mode mode,
+              tree maxwrite = NULL_TREE, bool minwrite = false,
+              tree maxread = NULL_TREE, bool minread = false)
+    : call (expr),
+      dst (maxwrite, minwrite), src (maxread, minread), mode (mode) { }
+
+  /* Built-in function call.  */
+  tree call;
   /* Destination and source of the access.  */
   access_ref dst, src;
+  /* Read-only for functions like memcmp or strlen, write-only
+     for memset, read-write for memcpy or strcat.  */
+  access_mode mode;
 };
 
-extern bool check_access (tree, tree, tree, tree, tree, tree, tree,
-                         bool = true, const access_data * = NULL);
+extern bool check_access (tree, tree, tree, tree, tree,
+                         access_mode, const access_data * = NULL);
 
 #endif /* GCC_BUILTINS_H */
index 2b1aca16eb4d7db976af75f4d73953de53594e8d..c1d8fd336e88136fbf09164289a47cb62dd1dea5 100644 (file)
@@ -823,6 +823,10 @@ C ObjC C++ LTO ObjC++ Joined RejectNegative UInteger Var(warn_stringop_overflow)
 Under the control of Object Size type, warn about buffer overflow in string
 manipulation functions like memcpy and strcpy.
 
+Wstringop-overread
+C ObjC C++ LTO ObjC++ Var(warn_stringop_overread) Init(1) Warning LangEnabledBy(C ObjC C++ LTO ObjC++, Wall)
+Warn about reading past the end of a source array in string manipulation functions like memchr and memcpy.
+
 Wstringop-truncation
 C ObjC C++ LTO ObjC++ Var(warn_stringop_truncation) Warning Init (1) LangEnabledBy(C ObjC C++ LTO ObjC++, Wall)
 Warn about truncation in string manipulation functions like strncat and strncpy.
index a11da66492d001cd0bd56f07a11e35c2bcf6e754..8ac94db68176f6dd2d00a59432b972c02460419b 100644 (file)
@@ -1274,7 +1274,7 @@ get_size_range (tree exp, tree range[2], bool allow_zero /* = false */)
   if (range_type == VR_VARYING)
     {
       if (integral)
-       {
+       {       
          /* Use the full range of the type of the expression when
             no value range information is available.  */
          range[0] = TYPE_MIN_VALUE (exptype);
@@ -1559,22 +1559,23 @@ get_attr_nonstring_decl (tree expr, tree *ref)
   return NULL_TREE;
 }
 
-/* Warn about passing a non-string array/pointer to a function that
-   expects a nul-terminated string argument.  */
+/* Warn about passing a non-string array/pointer to a built-in function
+   that expects a nul-terminated string argument.  Returns true if
+   a warning has been issued.*/
 
-void
+bool
 maybe_warn_nonstring_arg (tree fndecl, tree exp)
 {
   if (!fndecl || !fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
-    return;
+    return false;
 
-  if (TREE_NO_WARNING (exp) || !warn_stringop_overflow)
-    return;
+  if (TREE_NO_WARNING (exp) || !warn_stringop_overread)
+    return false;
 
   /* Avoid clearly invalid calls (more checking done below).  */
   unsigned nargs = call_expr_nargs (exp);
   if (!nargs)
-    return;
+    return false;
 
   /* The bound argument to a bounded string function like strncpy.  */
   tree bound = NULL_TREE;
@@ -1666,22 +1667,27 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp)
 
   if (bndrng[0])
     {
-      /* Diagnose excessive bound prior the adjustment below and
+      /* Diagnose excessive bound prior to the adjustment below and
         regardless of attribute nonstring.  */
       tree maxobjsize = max_object_size ();
       if (tree_int_cst_lt (maxobjsize, bndrng[0]))
        {
+         bool warned = false;
          if (tree_int_cst_equal (bndrng[0], bndrng[1]))
-           warning_at (loc, OPT_Wstringop_overflow_,
-                       "%K%qD specified bound %E "
-                       "exceeds maximum object size %E",
-                       exp, fndecl, bndrng[0], maxobjsize);
+           warned = warning_at (loc, OPT_Wstringop_overread,
+                                "%K%qD specified bound %E "
+                                "exceeds maximum object size %E",
+                                exp, fndecl, bndrng[0], maxobjsize);
          else
-           warning_at (loc, OPT_Wstringop_overflow_,
-                       "%K%qD specified bound [%E, %E] "
-                       "exceeds maximum object size %E",
-                       exp, fndecl, bndrng[0], bndrng[1], maxobjsize);
-         return;
+           warned = warning_at (loc, OPT_Wstringop_overread,
+                                "%K%qD specified bound [%E, %E] "
+                                "exceeds maximum object size %E",
+                                exp, fndecl, bndrng[0], bndrng[1],
+                                maxobjsize);
+         if (warned)
+           TREE_NO_WARNING (exp) = true;
+
+         return warned;
        }
     }
 
@@ -1710,6 +1716,7 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp)
        }
     }
 
+  bool any_arg_warned = false;
   /* Iterate over the built-in function's formal arguments and check
      each const char* against the actual argument.  If the actual
      argument is declared attribute non-string issue a warning unless
@@ -1820,19 +1827,19 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp)
       if (wi::ltu_p (asize, wibnd))
        {
          if (bndrng[0] == bndrng[1])
-           warned = warning_at (loc, OPT_Wstringop_overflow_,
+           warned = warning_at (loc, OPT_Wstringop_overread,
                                 "%qD argument %i declared attribute "
                                 "%<nonstring%> is smaller than the specified "
                                 "bound %wu",
                                 fndecl, argno + 1, wibnd.to_uhwi ());
          else if (wi::ltu_p (asize, wi::to_offset (bndrng[0])))
-           warned = warning_at (loc, OPT_Wstringop_overflow_,
+           warned = warning_at (loc, OPT_Wstringop_overread,
                                 "%qD argument %i declared attribute "
                                 "%<nonstring%> is smaller than "
                                 "the specified bound [%E, %E]",
                                 fndecl, argno + 1, bndrng[0], bndrng[1]);
          else
-           warned = warning_at (loc, OPT_Wstringop_overflow_,
+           warned = warning_at (loc, OPT_Wstringop_overread,
                                 "%qD argument %i declared attribute "
                                 "%<nonstring%> may be smaller than "
                                 "the specified bound [%E, %E]",
@@ -1842,14 +1849,22 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp)
        ; /* Avoid warning for calls to strncat() when the bound
             is equal to the size of the non-string argument.  */
       else if (!bound)
-       warned = warning_at (loc, OPT_Wstringop_overflow_,
+       warned = warning_at (loc, OPT_Wstringop_overread,
                             "%qD argument %i declared attribute %<nonstring%>",
                             fndecl, argno + 1);
 
       if (warned)
-       inform (DECL_SOURCE_LOCATION (decl),
-               "argument %qD declared here", decl);
+       {
+         inform (DECL_SOURCE_LOCATION (decl),
+                 "argument %qD declared here", decl);
+         any_arg_warned = true;
+       }
     }
+
+  if (any_arg_warned)
+    TREE_NO_WARNING (exp) = true;
+
+  return any_arg_warned;
 }
 
 /* Issue an error if CALL_EXPR was flagged as requiring
@@ -1896,11 +1911,11 @@ append_attrname (const std::pair<int, attr_access> &access,
   size_t len = strlen (attrstr);
 
   const char* const atname
-    = (access.second.mode == attr_access::read_only
+    = (access.second.mode == access_read_only
        ? "read_only"
-       : (access.second.mode == attr_access::write_only
+       : (access.second.mode == access_write_only
          ? "write_only"
-         : (access.second.mode == attr_access::read_write
+         : (access.second.mode == access_read_write
             ? "read_write" : "none")));
 
   const char *sep = len ? ", " : "";
@@ -2045,7 +2060,7 @@ maybe_warn_rdwr_sizes (rdwr_map *rwm, tree fndecl, tree fntype, tree exp)
       tree objsize = compute_objsize (ptr, 0);
 
       tree srcsize;
-      if (access.second.mode == attr_access::write_only)
+      if (access.second.mode == access_write_only)
        {
          /* For a write-only argument there is no source.  */
          srcsize = NULL_TREE;
@@ -2055,8 +2070,8 @@ maybe_warn_rdwr_sizes (rdwr_map *rwm, tree fndecl, tree fntype, tree exp)
          /* For read-only and read-write attributes also set the source
             size.  */
          srcsize = objsize;
-         if (access.second.mode == attr_access::read_only
-             || access.second.mode == attr_access::none)
+         if (access.second.mode == access_read_only
+             || access.second.mode == access_none)
            {
              /* For a read-only attribute there is no destination so
                 clear OBJSIZE.  This emits "reading N bytes" kind of
@@ -2070,8 +2085,8 @@ maybe_warn_rdwr_sizes (rdwr_map *rwm, tree fndecl, tree fntype, tree exp)
         iteration so that accesses via different arguments are
         diagnosed.  */
       TREE_NO_WARNING (exp) = false;
-      check_access (exp, NULL_TREE, NULL_TREE, size, /*maxread=*/ NULL_TREE,
-                   srcsize, objsize, access.second.mode != attr_access::none);
+      check_access (exp, size, /*maxread=*/ NULL_TREE, srcsize, objsize,
+                   access.second.mode);
 
       if (TREE_NO_WARNING (exp))
        /* If check_access issued a warning above, append the relevant
index 4ee493607774df26d88136272aa25c6e55c717f8..dfb951ca45b94e2545463fefead41db673e4596c 100644 (file)
@@ -132,7 +132,7 @@ extern bool reference_callee_copied (CUMULATIVE_ARGS *,
                                     const function_arg_info &);
 extern void maybe_warn_alloc_args_overflow (tree, tree, tree[2], int[2]);
 extern tree get_attr_nonstring_decl (tree, tree * = NULL);
-extern void maybe_warn_nonstring_arg (tree, tree);
+extern bool maybe_warn_nonstring_arg (tree, tree);
 extern bool get_size_range (tree, tree[2], bool = false);
 extern rtx rtx_for_static_chain (const_tree, bool);
 extern bool cxx17_empty_base_field_p (const_tree);
index c99924214a7a89eadf7018eb13d9e72f0feab69d..5d29a7fa23c07250a664a0dfd4ac56b8dca68df1 100644 (file)
@@ -366,7 +366,8 @@ Objective-C and Objective-C++ Dialects}.
 -Wstack-protector  -Wstack-usage=@var{byte-size}  -Wstrict-aliasing @gol
 -Wstrict-aliasing=n  -Wstrict-overflow  -Wstrict-overflow=@var{n} @gol
 -Wstring-compare @gol
--Wstringop-overflow=@var{n}  -Wno-stringop-truncation @gol
+-Wno-stringop-overflow -Wno-stringop-overread @gol
+-Wno-stringop-truncation @gol
 -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{|}malloc@r{]} @gol
 -Wswitch  -Wno-switch-bool  -Wswitch-default  -Wswitch-enum @gol
 -Wno-switch-outside-range  -Wno-switch-unreachable  -Wsync-nand @gol
@@ -6754,6 +6755,7 @@ void f (char *d)
 
 @option{-Wstring-compare} is enabled by @option{-Wextra}.
 
+@item -Wno-stringop-overflow
 @item -Wstringop-overflow
 @itemx -Wstringop-overflow=@var{type}
 @opindex Wstringop-overflow
@@ -6795,6 +6797,15 @@ const char* f (enum Color clr)
 
 Option @option{-Wstringop-overflow=2} is enabled by default.
 
+@item -Wno-stringop-overread
+@opindex Wstringop-overread
+@opindex Wno-stringop-overread
+Warn for calls to string manipulation functions such as @code{memchr},
+@code{strcpy} that are determined to read past the end of the source
+sequence. 
+
+Option @option{-Wstringop-overread} is enabled by default.
+
 @table @gcctabopt
 @item -Wstringop-overflow
 @itemx -Wstringop-overflow=1
@@ -7502,8 +7513,12 @@ This warning is also enabled by @option{-Wshadow=local}.
 Warn whenever an object is defined whose size exceeds @var{byte-size}.
 @option{-Wlarger-than=}@samp{PTRDIFF_MAX} is enabled by default.
 Warnings controlled by the option can be disabled either by specifying
-@var{byte-size} of @samp{SIZE_MAX} or more or by
-@option{-Wno-larger-than}.
+@var{byte-size} of @samp{SIZE_MAX} or more or by @option{-Wno-larger-than}.
+
+Also warn for calls to bounded functions such as @code{memchr} or
+@code{strnlen} that specify a bound greater than the largest possible
+object, which is @samp{PTRDIFF_MAX} bytes by default.  These warnings
+can only be disabled by @option{-Wno-larger-than}.
 
 @item -Wno-larger-than
 @opindex Wno-larger-than
index dcc1b56a2735515bd9267a1a4da7f869b430aba0..c3fa4cb7cc1b9097b521964604387392910b1139 100644 (file)
@@ -1875,7 +1875,7 @@ gimple_fold_builtin_strcpy (gimple_stmt_iterator *gsi,
     {
       /* Avoid folding calls with unterminated arrays.  */
       if (!gimple_no_warning_p (stmt))
-       warn_string_no_nul (loc, "strcpy", src, nonstr);
+       warn_string_no_nul (loc, NULL_TREE, "strcpy", src, nonstr);
       gimple_set_no_warning (stmt, true);
       return false;
     }
@@ -3074,11 +3074,16 @@ gimple_fold_builtin_stpcpy (gimple_stmt_iterator *gsi)
 
   /* Set to non-null if ARG refers to an unterminated array.  */
   c_strlen_data data = { };
+  /* The size of the unterminated array if SRC referes to one.  */
+  tree size;
+  /* True if the size is exact/constant, false if it's the lower bound
+     of a range.  */
+  bool exact;
   tree len = c_strlen (src, 1, &data, 1);
   if (!len
       || TREE_CODE (len) != INTEGER_CST)
     {
-      data.decl = unterminated_array (src);
+      data.decl = unterminated_array (src, &size, &exact);
       if (!data.decl)
        return false;
     }
@@ -3087,7 +3092,8 @@ gimple_fold_builtin_stpcpy (gimple_stmt_iterator *gsi)
     {
       /* Avoid folding calls with unterminated arrays.  */
       if (!gimple_no_warning_p (stmt))
-       warn_string_no_nul (loc, "stpcpy", src, data.decl);
+       warn_string_no_nul (loc, NULL_TREE, "stpcpy", src, data.decl, size,
+                           exact);
       gimple_set_no_warning (stmt, true);
       return false;
     }
index 668e809620071553c6ca6d40fa3175972ae2f07a..131645406dd42ff7039dc2703c83cda1bbfacadf 100644 (file)
@@ -29,52 +29,52 @@ void sink (unsigned);
 
 void test_zero_length_array (void)
 {
-  T (a0.a);                   // { dg-warning "\\\[-Warray-bounds" }
-  T (a0.a - 1);               // { dg-warning "\\\[-Warray-bounds" }
-  T (a0.a + 1);               // { dg-warning "\\\[-Warray-bounds" }
-  T (a0.a + 9);               // { dg-warning "\\\[-Warray-bounds" }
-  T (a0.a + INT_MAX);         // { dg-warning "\\\[-Warray-bounds" }
-  T (a0.a + PTRDIFF_MAX);     // { dg-warning "\\\[-Warray-bounds" }
+  T (a0.a);                   // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a0.a - 1);               // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a0.a + 1);               // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a0.a + 9);               // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a0.a + INT_MAX);         // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a0.a + PTRDIFF_MAX);     // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
   T (a0.a + SIZE_MAX);        // { dg-warning "\\\[-Warray-bounds" }
 
   T (a0_0.a);                 // { dg-warning "\\\[-Warray-bounds" }
   T (a0_0.a - 1);             // { dg-warning "\\\[-Warray-bounds" }
-  T (a0_0.a + 1);             // { dg-warning "\\\[-Warray-bounds" }
-  T (a0_0.a + 9);             // { dg-warning "\\\[-Warray-bounds" }
-  T (a0_0.a + INT_MAX);       // { dg-warning "\\\[-Warray-bounds" }
-  T (a0_0.a + PTRDIFF_MAX);   // { dg-warning "\\\[-Warray-bounds" }
+  T (a0_0.a + 1);             // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a0_0.a + 9);             // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a0_0.a + INT_MAX);       // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a0_0.a + PTRDIFF_MAX);   // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
   T (a0_0.a + SIZE_MAX);      // { dg-warning "\\\[-Warray-bounds" }
 
   T (a0_0_.a);                // { dg-warning "\\\[-Warray-bounds" }
   T (a0_0_.a - 1);            // { dg-warning "\\\[-Warray-bounds" }
-  T (a0_0_.a + 1);            // { dg-warning "\\\[-Warray-bounds" }
-  T (a0_0_.a + 9);            // { dg-warning "\\\[-Warray-bounds" }
-  T (a0_0_.a + INT_MAX);      // { dg-warning "\\\[-Warray-bounds" }
-  T (a0_0_.a + PTRDIFF_MAX);  // { dg-warning "\\\[-Warray-bounds" }
+  T (a0_0_.a + 1);            // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a0_0_.a + 9);            // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a0_0_.a + INT_MAX);      // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a0_0_.a + PTRDIFF_MAX);  // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
   T (a0_0_.a + SIZE_MAX);     // { dg-warning "\\\[-Warray-bounds" }
 }
 
 void test_one_element_array (void)
 {
   T (a1.a - 1);               // { dg-warning "\\\[-Warray-bounds" }
-  T (a1.a + 1);               // { dg-warning "\\\[-Warray-bounds" }
-  T (a1.a + 9);               // { dg-warning "\\\[-Warray-bounds" }
-  T (a1.a + INT_MAX);         // { dg-warning "\\\[-Warray-bounds" }
-  T (a1.a + PTRDIFF_MAX);     // { dg-warning "\\\[-Warray-bounds" }
+  T (a1.a + 1);               // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a1.a + 9);               // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a1.a + INT_MAX);         // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a1.a + PTRDIFF_MAX);     // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
   T (a1.a + SIZE_MAX);        // { dg-warning "\\\[-Warray-bounds" }
 
   T (a1_0.a - 1);             // { dg-warning "\\\[-Warray-bounds" }
-  T (a1_0.a + 1);             // { dg-warning "\\\[-Warray-bounds" }
-  T (a1_0.a + 9);             // { dg-warning "\\\[-Warray-bounds" }
-  T (a1_0.a + INT_MAX);       // { dg-warning "\\\[-Warray-bounds" }
-  T (a1_0.a + PTRDIFF_MAX);   // { dg-warning "\\\[-Warray-bounds" }
+  T (a1_0.a + 1);             // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a1_0.a + 9);             // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a1_0.a + INT_MAX);       // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a1_0.a + PTRDIFF_MAX);   // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
   T (a1_0.a + SIZE_MAX);      // { dg-warning "\\\[-Warray-bounds" }
 
   T (a1_0_.a - 1);            // { dg-warning "\\\[-Warray-bounds" }
-  T (a1_0_.a + 1);            // { dg-warning "\\\[-Warray-bounds" }
-  T (a1_0_.a + 9);            // { dg-warning "\\\[-Warray-bounds" }
-  T (a1_0_.a + INT_MAX);      // { dg-warning "\\\[-Warray-bounds" }
-  T (a1_0_.a + PTRDIFF_MAX);  // { dg-warning "\\\[-Warray-bounds" }
+  T (a1_0_.a + 1);            // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a1_0_.a + 9);            // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a1_0_.a + INT_MAX);      // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (a1_0_.a + PTRDIFF_MAX);  // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
   T (a1_0_.a + SIZE_MAX);     // { dg-warning "\\\[-Warray-bounds" }
 }
 
@@ -82,26 +82,25 @@ void test_flexible_array_member (void)
 {
   T (ax.a);                   // { dg-warning "\\\[-Warray-bounds" }
   T (ax.a - 1);               // { dg-warning "\\\[-Warray-bounds" }
-  T (ax.a + 1);               // { dg-warning "\\\[-Warray-bounds" }
-  T (ax.a + 9);               // { dg-warning "\\\[-Warray-bounds" }
-  T (ax.a + INT_MAX);         // { dg-warning "\\\[-Warray-bounds" }
-  T (ax.a + PTRDIFF_MAX);     // { dg-warning "\\\[-Warray-bounds" }
+  T (ax.a + 1);               // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (ax.a + 9);               // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (ax.a + INT_MAX);         // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (ax.a + PTRDIFF_MAX);     // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
   T (ax.a + SIZE_MAX);        // { dg-warning "\\\[-Warray-bounds" }
 
   T (ax_0.a);                 // { dg-warning "\\\[-Warray-bounds" }
   T (ax_0.a - 1);             // { dg-warning "\\\[-Warray-bounds" }
-  T (ax_0.a + 1);             // { dg-warning "\\\[-Warray-bounds" }
-  T (ax_0.a + 9);             // { dg-warning "\\\[-Warray-bounds" }
-  T (ax_0.a + INT_MAX);       // { dg-warning "\\\[-Warray-bounds" }
-  T (ax_0.a + PTRDIFF_MAX);   // { dg-warning "\\\[-Warray-bounds" }
+  T (ax_0.a + 1);             // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (ax_0.a + 9);             // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (ax_0.a + INT_MAX);       // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (ax_0.a + PTRDIFF_MAX);   // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
   T (ax_0.a + SIZE_MAX);      // { dg-warning "\\\[-Warray-bounds" }
 
   T (ax_0_.a);                // { dg-warning "\\\[-Warray-bounds" }
   T (ax_0_.a - 1);            // { dg-warning "\\\[-Warray-bounds" }
-  T (ax_0_.a + 1);            // { dg-warning "\\\[-Warray-bounds" }
-  T (ax_0_.a + 9);            // { dg-warning "\\\[-Warray-bounds" }
-  T (ax_0_.a + INT_MAX);      // { dg-warning "\\\[-Warray-bounds" }
-  T (ax_0_.a + PTRDIFF_MAX);  // { dg-warning "\\\[-Warray-bounds" }
+  T (ax_0_.a + 1);            // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (ax_0_.a + 9);            // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (ax_0_.a + INT_MAX);      // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  T (ax_0_.a + PTRDIFF_MAX);  // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
   T (ax_0_.a + SIZE_MAX);     // { dg-warning "\\\[-Warray-bounds" }
 }
-
index eb074a13e7d12c5471f35dce40f0aa63a37efc18..3b019c8a80ebfd5b3a1ed654c30a185bb6317de0 100644 (file)
@@ -637,9 +637,7 @@ void test_strcpy_cst (ptrdiff_t i)
   T ("012", a, a + 1);            /* { dg-warning "accessing 3 bytes at offsets 0 and 1 overlaps 2 bytes at offset 1" "strcpy" } */
   T ("012", a, a + 2);
   T ("012", a, a + 3);
-  /* The following doesn't overlap but it should trigger -Wstringop-overflow
-     for reading past the end.  */
-  T ("012", a, a + sizeof a);     /* { dg-warning "\\\[-Wstringop-overflow" "pr81437" { xfail *-*-* } } */
+  T ("012", a, a + sizeof a);     /* { dg-warning "\\\[-Wstringop-overread" "pr81437" } */
 
   /* The terminating nul written to d[2] overwrites s[0].  */
   T ("0123", a, a + 2);           /* { dg-warning "accessing 3 bytes at offsets 0 and 2 overlaps 1 byte at offset 2" } */
index b1eb8b63004268d0605ac80c38e8f6778099c2a3..e3ceabd0836a977820d69130685313ae63ef69bb 100644 (file)
@@ -379,9 +379,9 @@ void test_stnrdup_warn (struct MemArrays *p)
   T (strndup (p->arr, N));
 
 
-  T (strndup (arr, N + 1));     /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound 5" } */
+  T (strndup (arr, N + 1));     /* { dg-warning "specified bound 5 exceeds source size 4" } */
   T (strndup (parr, N + 1));
-  T (strndup (p->arr, N + 1));  /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound 5" } */
+  T (strndup (p->arr, N + 1));  /* { dg-warning "specified bound 5 exceeds source size 4" } */
   T (strndup (p->parr, N + 1));
 }
 
index 19ceaacf39c24cd89e7487673f573b9c997b066d..4b804b3f10751f3d640a72f361c3a2ab5e015c98 100644 (file)
@@ -1,7 +1,7 @@
 /* PR 85623 - strncmp() warns about attribute 'nonstring' incorrectly
    in -Wstringop-overflow
   { dg-do compile }
-  { dg-options "-O2 -Wstringop-overflow -ftrack-macro-expansion=0" } */
+  { dg-options "-O2 -Wstringop-overread -ftrack-macro-expansion=0" } */
 
 #include "../gcc.dg/range.h"
 
@@ -41,15 +41,15 @@ void test_strcmp_cst (void)
   T (strcmp (S (1), a3));
   T (strcmp (S (2), a3));
   /* The following reads a3[3].  */
-  T (strcmp (S (3), a3));   /* { dg-warning "\\\[-Wstringop-overflow" } */
+  T (strcmp (S (3), a3));   /* { dg-warning "\\\[-Wstringop-overread" } */
   /* The following also reads past the end of a3.  */
-  T (strcmp (S (9), a3));   /* { dg-warning "\\\[-Wstringop-overflow" } */
+  T (strcmp (S (9), a3));   /* { dg-warning "\\\[-Wstringop-overread" } */
 
   T (strcmp (a3, S (0)));
   T (strcmp (a3, S (1)));
   T (strcmp (a3, S (2)));
-  T (strcmp (a3, S (3)));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-  T (strcmp (a3, S (9)));   /* { dg-warning "\\\[-Wstringop-overflow" } */
+  T (strcmp (a3, S (3)));   /* { dg-warning "\\\[-Wstringop-overread" } */
+  T (strcmp (a3, S (9)));   /* { dg-warning "\\\[-Wstringop-overread" } */
 }
 
 
@@ -62,16 +62,16 @@ void test_strcmp_range (const char *s)
   T (strcmp (a3, s));
 
   s = signed_value () < 0 ? S (0) : S (3);
-  T (strcmp (a3, s));       /* { dg-warning "\\\[-Wstringop-overflow" } */
+  T (strcmp (a3, s));       /* { dg-warning "\\\[-Wstringop-overread" } */
 
   s = signed_value () < 0 ? S (1) : S (2);
   T (strcmp (a3, s));
 
   s = signed_value () < 0 ? S (1) : S (3);
-  T (strcmp (a3, s));       /* { dg-warning "\\\[-Wstringop-overflow" } */
+  T (strcmp (a3, s));       /* { dg-warning "\\\[-Wstringop-overread" } */
 
   s = signed_value () < 0 ? S (3) : S (4);
-  T (strcmp (a3, s));       /* { dg-warning "\\\[-Wstringop-overflow" } */
+  T (strcmp (a3, s));       /* { dg-warning "\\\[-Wstringop-overread" } */
 }
 
 
@@ -81,21 +81,21 @@ void test_strncmp_cst (void)
   T (strncmp (S (1), a3, 2));
   T (strncmp (S (2), a3, 3));
   T (strncmp (S (3), a3, 3));
-  T (strncmp (S (3), a3, 4));   /* { dg-warning "\\\[-Wstringop-overflow" } */
+  T (strncmp (S (3), a3, 4));   /* { dg-warning "\\\[-Wstringop-overread" } */
 
   T (strncmp (S (9), a3, 3));
-  T (strncmp (S (9), a3, 4));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-  T (strncmp (S (9), a3, 5));   /* { dg-warning "\\\[-Wstringop-overflow" } */
+  T (strncmp (S (9), a3, 4));   /* { dg-warning "\\\[-Wstringop-overread" } */
+  T (strncmp (S (9), a3, 5));   /* { dg-warning "\\\[-Wstringop-overread" } */
 
   T (strncmp (a3, S (0), 1));
   T (strncmp (a3, S (1), 2));
   T (strncmp (a3, S (2), 3));
   T (strncmp (a3, S (3), 3));
-  T (strncmp (a3, S (3), 4));   /* { dg-warning "\\\[-Wstringop-overflow" } */
+  T (strncmp (a3, S (3), 4));   /* { dg-warning "\\\[-Wstringop-overread" } */
 
   T (strncmp (a3, S (9), 3));
-  T (strncmp (a3, S (9), 4));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-  T (strncmp (a3, S (9), 5));   /* { dg-warning "\\\[-Wstringop-overflow" } */
+  T (strncmp (a3, S (9), 4));   /* { dg-warning "\\\[-Wstringop-overread" } */
+  T (strncmp (a3, S (9), 5));   /* { dg-warning "\\\[-Wstringop-overread" } */
 }
 
 void test_strncmp_range (const char *s)
@@ -110,8 +110,8 @@ void test_strncmp_range (const char *s)
   T (strncmp (a3, S (5), UR (1, 4)));
   T (strncmp (a3, S (5), UR (2, 5)));
   T (strncmp (a3, S (5), UR (3, 6)));
-  T (strncmp (a3, S (5), UR (4, 7)));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-  T (strncmp (a3, S (5), UR (7, 9)));   /* { dg-warning "\\\[-Wstringop-overflow" } */
+  T (strncmp (a3, S (5), UR (4, 7)));   /* { dg-warning "\\\[-Wstringop-overread" } */
+  T (strncmp (a3, S (5), UR (7, 9)));   /* { dg-warning "\\\[-Wstringop-overread" } */
 
   s = signed_value () < 0 ? S (0) : S (1);
   T (strncmp (a3, s, UR (1, 3)));
@@ -124,7 +124,7 @@ void test_strncmp_range (const char *s)
   T (strncmp (a3, s, UR (1, 4)));
   T (strncmp (a3, s, UR (2, 5)));
   T (strncmp (a3, s, UR (3, 6)));
-  T (strncmp (a3, s, UR (4, 7)));       /* { dg-warning "\\\[-Wstringop-overflow" } */
+  T (strncmp (a3, s, UR (4, 7)));       /* { dg-warning "\\\[-Wstringop-overread" } */
 }
 
 void test_strncasecmp (void)
@@ -133,21 +133,21 @@ void test_strncasecmp (void)
   T (strncasecmp (S (1), a3, 2));
   T (strncasecmp (S (2), a3, 3));
   T (strncasecmp (S (3), a3, 3));
-  T (strncasecmp (S (3), a3, 4));   /* { dg-warning "\\\[-Wstringop-overflow" } */
+  T (strncasecmp (S (3), a3, 4));   /* { dg-warning "\\\[-Wstringop-overread" } */
 
   T (strncasecmp (S (9), a3, 3));
-  T (strncasecmp (S (9), a3, 4));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-  T (strncasecmp (S (9), a3, 5));   /* { dg-warning "\\\[-Wstringop-overflow" } */
+  T (strncasecmp (S (9), a3, 4));   /* { dg-warning "\\\[-Wstringop-overread" } */
+  T (strncasecmp (S (9), a3, 5));   /* { dg-warning "\\\[-Wstringop-overread" } */
 
   T (strncasecmp (a3, S (0), 1));
   T (strncasecmp (a3, S (1), 2));
   T (strncasecmp (a3, S (2), 3));
   T (strncasecmp (a3, S (3), 3));
-  T (strncasecmp (a3, S (3), 4));   /* { dg-warning "\\\[-Wstringop-overflow" } */
+  T (strncasecmp (a3, S (3), 4));   /* { dg-warning "\\\[-Wstringop-overread" } */
 
   T (strncasecmp (a3, S (9), 3));
-  T (strncasecmp (a3, S (9), 4));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-  T (strncasecmp (a3, S (9), 5));   /* { dg-warning "\\\[-Wstringop-overflow" } */
+  T (strncasecmp (a3, S (9), 4));   /* { dg-warning "\\\[-Wstringop-overread" } */
+  T (strncasecmp (a3, S (9), 5));   /* { dg-warning "\\\[-Wstringop-overread" } */
 }
 
 void test_strspn (void)
@@ -155,31 +155,31 @@ void test_strspn (void)
   /* strspn must traverse all characters in the second argument except
      when the first string is empty. */
   T (strspn (S (0), a3));
-  T (strspn (S (1), a3));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-  T (strspn (S (2), a3));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-  T (strspn (S (3), a3));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-  T (strspn (S (9), a3));   /* { dg-warning "\\\[-Wstringop-overflow" } */
+  T (strspn (S (1), a3));   /* { dg-warning "\\\[-Wstringop-overread" } */
+  T (strspn (S (2), a3));   /* { dg-warning "\\\[-Wstringop-overread" } */
+  T (strspn (S (3), a3));   /* { dg-warning "\\\[-Wstringop-overread" } */
+  T (strspn (S (9), a3));   /* { dg-warning "\\\[-Wstringop-overread" } */
 
   /* Similarly, strspn must traverse all characters in the first argument
      except when the second string is empty. */
   T (strspn (a3, S (0)));
-  T (strspn (a3, S (1)));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-  T (strspn (a3, S (2)));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-  T (strspn (a3, S (3)));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-  T (strspn (a3, S (9)));   /* { dg-warning "\\\[-Wstringop-overflow" } */
+  T (strspn (a3, S (1)));   /* { dg-warning "\\\[-Wstringop-overread" } */
+  T (strspn (a3, S (2)));   /* { dg-warning "\\\[-Wstringop-overread" } */
+  T (strspn (a3, S (3)));   /* { dg-warning "\\\[-Wstringop-overread" } */
+  T (strspn (a3, S (9)));   /* { dg-warning "\\\[-Wstringop-overread" } */
 }
 
 void test_strcspn (void)
 {
   T (strcspn (S (0), a3));
-  T (strcspn (S (1), a3));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-  T (strcspn (S (2), a3));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-  T (strcspn (S (3), a3));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-  T (strcspn (S (9), a3));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-
-  T (strcspn (a3, S (0)));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-  T (strcspn (a3, S (1)));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-  T (strcspn (a3, S (2)));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-  T (strcspn (a3, S (3)));   /* { dg-warning "\\\[-Wstringop-overflow" } */
-  T (strcspn (a3, S (9)));   /* { dg-warning "\\\[-Wstringop-overflow" } */
+  T (strcspn (S (1), a3));   /* { dg-warning "\\\[-Wstringop-overread" } */
+  T (strcspn (S (2), a3));   /* { dg-warning "\\\[-Wstringop-overread" } */
+  T (strcspn (S (3), a3));   /* { dg-warning "\\\[-Wstringop-overread" } */
+  T (strcspn (S (9), a3));   /* { dg-warning "\\\[-Wstringop-overread" } */
+
+  T (strcspn (a3, S (0)));   /* { dg-warning "\\\[-Wstringop-overread" } */
+  T (strcspn (a3, S (1)));   /* { dg-warning "\\\[-Wstringop-overread" } */
+  T (strcspn (a3, S (2)));   /* { dg-warning "\\\[-Wstringop-overread" } */
+  T (strcspn (a3, S (3)));   /* { dg-warning "\\\[-Wstringop-overread" } */
+  T (strcspn (a3, S (9)));   /* { dg-warning "\\\[-Wstringop-overread" } */
 }
index fbae8bae5f73debc1de0d597ff67b60af3bbd3ef..9ad33425b27a22e09fb74220731cad150fbc18eb 100644 (file)
@@ -85,7 +85,7 @@ void test_strncat_nonstring_var (char *d, size_t n)
   T (strncat (nd3, ns5, UR (1, 2)));
   T (strncat (nd3, ns5, UR (2, 3)));
   T (strncat (nd3, ns5, UR (3, 4)));
-  T (strncat (nd3, ns5, UR (4, 5)));  /* { dg-warning "specified bound between 4 and 5 exceeds destination size 3" } */
+  T (strncat (nd3, ns5, UR (4, 5)));  /* { dg-warning "specified bound \\\[4, 5] exceeds destination size 3" } */
 
   T (strncat (nd5, ns3, UR (0, 1)));
   T (strncat (nd5, ns3, UR (1, 2)));
index 635d5f40ef79f24d991598e9a8b2c67c49c1e1eb..d283cbfd596794f5be2aa4532ac733496706856a 100644 (file)
@@ -1,6 +1,6 @@
 // Test -Wsizeof-pointer-memaccess warnings.
 // { dg-do compile }
-// { dg-options "-Wall -Wno-array-bounds -Wno-sizeof-array-argument -Wno-stringop-overflow -Wno-stringop-truncation" }
+// { dg-options "-Wall -Wno-array-bounds -Wno-sizeof-array-argument -Wno-stringop-overflow -Wno-stringop-overread -Wno-stringop-truncation" }
 // Test just twice, once with -O0 non-fortified, once with -O2 fortified.
 // { dg-skip-if "" { *-*-* }  { "*" } { "-O0" "-O2" } }
 // { dg-skip-if "" { *-*-* }  { "-flto" } { "" } }
index b566c2aa52dad662d1ed90390328014960676bcc..fe24cddfeaa5f7146ae53769a2b2a9f8585c937b 100644 (file)
@@ -1,6 +1,6 @@
 // Test -Wsizeof-pointer-memaccess warnings.
 // { dg-do compile }
-// { dg-options "-Wall -Wno-array-bounds -Wno-sizeof-array-argument -Wno-stringop-overflow -Wno-stringop-truncation" }
+// { dg-options "-Wall -Wno-array-bounds -Wno-sizeof-array-argument -Wno-stringop-overflow -Wno-stringop-overread -Wno-stringop-truncation" }
 // Test just twice, once with -O0 non-fortified, once with -O2 fortified,
 // suppressing buffer overflow warnings.
 // { dg-skip-if "" { *-*-* }  { "*" } { "-O0" "-O2" } }
index f10ffaca5cb18b1185033d870ed03e888991871b..83176564bc3541512bc55ef2a4bb5a63c2b6bd36 100644 (file)
@@ -21,65 +21,65 @@ char d[4];
 
 void* test_memcpy_s0_1 (void *d)
 {
-  return memcpy (d, s0, 1);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return memcpy (d, s0, 1);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 void* test_memcpy_s0_2 (void *d)
 {
-  return memcpy (d, s0, 2);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return memcpy (d, s0, 2);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 void* test_memcpy_s0_0_1 (void *d)
 {
-  return memcpy (d, s0_0, 1);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return memcpy (d, s0_0, 1);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 void* test_memcpy_s0_0_2 (void *d)
 {
-  return memcpy (d, s0_0, 2);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return memcpy (d, s0_0, 2);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 
 void* test_memcpy_s0_1_1 (void *d)
 {
-  return memcpy (d, s0_1, 1);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return memcpy (d, s0_1, 1);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 void* test_memcpy_s0_1_2 (void *d)
 {
-  return memcpy (d, s0_1, 2);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return memcpy (d, s0_1, 2);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 
 void* test_memcpy_s1_0_1 (void *d)
 {
-  return memcpy (d, s1_0, 1);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return memcpy (d, s1_0, 1);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 void* test_memcpy_s1_0_2 (void *d)
 {
-  return memcpy (d, s1_0, 2);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return memcpy (d, s1_0, 2);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 
 void* test_memmove_s0_1 (void *d)
 {
-  return memmove (d, s0, 1);      /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return memmove (d, s0, 1);      /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 void* test_memmove_s0_2 (void *d)
 {
-  return memmove (d, s0, 2);      /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return memmove (d, s0, 2);      /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 void* test_memmove_s0_0_1 (void *d)
 {
-  return memmove (d, s0_0, 1);    /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return memmove (d, s0_0, 1);    /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 void* test_memmove_s0_0_2 (void *d)
 {
-  return memmove (d, s0_0, 2);    /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return memmove (d, s0_0, 2);    /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 
@@ -92,57 +92,57 @@ const struct Empty e1_0[1][0] = { };
 
 void* test_memcpy_e_1 (void *d)
 {
-  return memcpy (d, &e, 1);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return memcpy (d, &e, 1);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 void* test_memcpy_e0_1 (void *d)
 {
-  return memcpy (d, e0, 1);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return memcpy (d, e0, 1);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 void* test_memcpy_e0_0_1 (void *d)
 {
-  return memcpy (d, e0_0, 1);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return memcpy (d, e0_0, 1);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 void* test_memcpy_e0_1_1 (void *d)
 {
-  return memcpy (d, e0_1, 1);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return memcpy (d, e0_1, 1);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 void* test_memcpy_e1_0_1 (void *d)
 {
-  return memcpy (d, e1_0, 1);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return memcpy (d, e1_0, 1);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 
 char* test_strcpy_s0 (char *d)
 {
-  return strcpy (d, s0);          /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return strcpy (d, s0);          /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 char* test_strcpy_s0_0 (char *d)
 {
-  return strcpy (d, s0_0[0]);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return strcpy (d, s0_0[0]);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 
 char* test_strncpy_s0_1 (char *d)
 {
-  return strncpy (d, s0, 1);    /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return strncpy (d, s0, 1);    /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 char* test_strncpy_s0_2 (char *d)
 {
-  return strncpy (d, s0, 2);    /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return strncpy (d, s0, 2);    /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 char* test_strncpy_s0_0_1 (char *d)
 {
-  return strncpy (d, s0_0[0], 1); /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return strncpy (d, s0_0[0], 1); /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
 
 char* test_strncpy_s0_0_2 (char *d)
 {
-  return strncpy (d, s0_0[0], 2); /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
+  return strncpy (d, s0_0[0], 2); /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" } */
 }
index aabc2832b3a456eb614b5008dc4eea5513e6014b..c389d96a98b02ba30bf24b6e52d81d4f4f0f2dd0 100644 (file)
@@ -3,7 +3,7 @@
    functions when -Wstringop-overflow is disabled is -Warray-bounds
    with the right wording.
    { dg-do compile }
-   { dg-options "-O2 -Wall -Wno-stringop-overflow" } */
+   { dg-options "-O2 -Wall -Wno-stringop-overflow -Wno-stringop-overread" } */
 
 #define PTRDIFF_MAX   __PTRDIFF_MAX__
 #define SIZE_MAX      __SIZE_MAX__
index 7bd6df2bf2e0539ae33596e8236d3e8f69a09cec..7c469e2aefc6a454d714b255fa5204a7fe0ceca9 100644 (file)
@@ -15,8 +15,8 @@ void fa0_extern (void)
 {
   sink (strlen (ea0.a - 2));    // { dg-warning "\\\[-Warray-bounds" }
   sink (strlen (ea0.a - 1));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
-  sink (strlen (ea0.a));        // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
-  sink (strlen (ea0.a + 1));    // { dg-warning "\\\[-Warray-bounds" }
+  sink (strlen (ea0.a));        // { dg-warning "\\\[-Wstringop-overread" "pr93514" }
+  sink (strlen (ea0.a + 1));    // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
 }
 
 static struct A0 sa0 = { 0 };
@@ -25,8 +25,8 @@ void fa0_static (void)
 {
   sink (strlen (sa0.a - 2));    // { dg-warning "\\\[-Warray-bounds" }
   sink (strlen (sa0.a - 1));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
-  sink (strlen (sa0.a));        // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
-  sink (strlen (sa0.a + 1));    // { dg-warning "\\\[-Warray-bounds" }
+  sink (strlen (sa0.a));        // { dg-warning "\\\[-Wstringop-overread" "pr93514" }
+  sink (strlen (sa0.a + 1));    // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
 }
 
 
@@ -52,23 +52,23 @@ void fax_static (void)
   sink (strlen (ax0.a - 2));    // { dg-warning "\\\[-Warray-bounds" }
   sink (strlen (ax0.a - 1));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
   sink (strlen (ax0.a));
-  sink (strlen (ax0.a + 1));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
-  sink (strlen (ax0.a + 2));    // { dg-warning "\\\[-Warray-bounds" }
+  sink (strlen (ax0.a + 1));    // { dg-warning "\\\[-Wstringop-overread" "pr93514" }
+  sink (strlen (ax0.a + 2));    // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
 
   sink (strlen (ax1.a - 2));    // { dg-warning "\\\[-Warray-bounds" }
   sink (strlen (ax1.a - 1));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
   sink (strlen (ax1.a));
   sink (strlen (ax1.a + 1));
-  sink (strlen (ax1.a + 2));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
-  sink (strlen (ax1.a + 3));    // { dg-warning "\\\[-Warray-bounds" }
+  sink (strlen (ax1.a + 2));    // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" "pr93514" }
+  sink (strlen (ax1.a + 3));    // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
 
   sink (strlen (ax2.a - 2));    // { dg-warning "\\\[-Warray-bounds" }
   sink (strlen (ax2.a - 1));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
   sink (strlen (ax2.a));
   sink (strlen (ax2.a + 1));
   sink (strlen (ax2.a + 2));
-  sink (strlen (ax2.a + 3));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
-  sink (strlen (ax2.a + 4));    // { dg-warning "\\\[-Warray-bounds" }
+  sink (strlen (ax2.a + 3));    // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" "pr93514" }
+  sink (strlen (ax2.a + 4));    // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
 
   sink (strlen (ax3.a - 2));    // { dg-warning "\\\[-Warray-bounds" }
   sink (strlen (ax3.a - 1));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
@@ -76,6 +76,6 @@ void fax_static (void)
   sink (strlen (ax3.a + 1));
   sink (strlen (ax3.a + 2));
   sink (strlen (ax3.a + 3));
-  sink (strlen (ax3.a + 4));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
-  sink (strlen (ax3.a + 5));    // { dg-warning "\\\[-Warray-bounds" }
+  sink (strlen (ax3.a + 4));    // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" "pr93514" }
+  sink (strlen (ax3.a + 5));    // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
 }
index 4d14de28b10a250a231fc0c9ed93e33de5bad54e..5aea89a08791a30b90b2d73175af1720e73aa92e 100644 (file)
@@ -1,6 +1,6 @@
 /* Test -Wsizeof-pointer-memaccess warnings.  */
 /* { dg-do compile } */
-/* { dg-options "-Wall -Wno-array-bounds -Wno-sizeof-array-argument -Wno-stringop-overflow" } */
+/* { dg-options "-Wall -Wno-array-bounds -Wno-sizeof-array-argument -Wno-stringop-overflow -Wno-stringop-overread" } */
 /* { dg-require-effective-target alloca } */
 
 typedef __SIZE_TYPE__ size_t;
index a81ab99d72451f86d88c934a964f4f863495dba4..8eaaa71327573741b3e41958ca81ab591ffaa851 100644 (file)
@@ -48,11 +48,18 @@ T (rindex, b + 4, '4');     // { dg-warning "missing terminating nul" "rindex" }
 T (stpcpy, d, a);           // { dg-warning "missing terminating nul" "stpcpy" }
 
 T (stpncpy, d, a, 4);
-T (stpncpy, d, a, 5);       // { dg-warning "missing terminating nul" "stpncpy" }
+T (stpncpy, d, a, 5);       // { dg-warning "specified bound 5 exceeds the size 4 of unterminated array" "stpncpy" }
 T (stpncpy, d, a, n);
 
-T (stpncpy, d, a + n, 4);
-T (stpncpy, d, a + n, 5);   // { dg-warning "missing terminating nul" "stpncpy" }
+/* When the offset into an unterminated array isn't known and the bound
+   is less than the size of the array it suggests the access may be
+   constrained just right.  When the bound is exactly equal to the size
+   of the array, then the offset would have to be zero for the access to
+   be safe, so a warning is justified.  Otherwise, the bound is too small
+   and the access is definitely unsafe.  */
+T (stpncpy, d, a + n, 3);
+T (stpncpy, d, a + n, 4);   // { dg-warning "specified bound 4 may exceed the size of at most 4 of unterminated array" "stpncpy" }
+T (stpncpy, d, a + n, 5);   // { dg-warning "specified bound 5 exceeds the size of at most 4 of unterminated array" "stpncpy" }
 
 T (stpncpy, d, b, 4);
 T (stpncpy, d, b, 5);
@@ -67,7 +74,7 @@ T (stpncpy, d, b + 3, 5);
 T (stpncpy, d, b + 3, n);
 
 T (stpncpy, d, b + 4, 1);
-T (stpncpy, d, b + 4, 2);   // { dg-warning "missing terminating nul" "stpncpy" }
+T (stpncpy, d, b + 4, 2);   // { dg-warning "specified bound 2 exceeds the size 1 of unterminated array" "stpncpy" }
 T (stpncpy, d, b + 4, n);
 /* The following might be worth warning about since it's only safe with
    n < 4.  */
@@ -84,7 +91,7 @@ T (strcasecmp, b, b + 4);   // { dg-warning "missing terminating nul" "strcasecm
 T (strcat, d, a);           // { dg-warning "missing terminating nul" "strcat" }
 
 T (strncat, d, a, 4);
-T (strncat, d, a, 5);       // { dg-warning "missing terminating nul" "strncat" }
+T (strncat, d, a, 5);       // { dg-warning "specified bound 5 exceeds the size 4 of unterminated array" "strncat" }
 T (strncat, d, a, n);
 
 T (strncat, d, b, n);
@@ -93,7 +100,7 @@ T (strncat, d, b + 2, n);
 T (strncat, d, b + 3, n);
 T (strncat, d, b + 4, 0);
 T (strncat, d, b + 4, 1);
-T (strncat, d, b + 4, 2);   // { dg-warning "missing terminating nul" "strncat" }
+T (strncat, d, b + 4, 2);   // { dg-warning "specified bound 2 exceeds the size 1 of unterminated array" "strncat" }
 /* The following should probably trigger a warning since it's only safe
    when n < 2, makes little sense with n == 0, and not much more with
    n == 1.  */
@@ -122,8 +129,8 @@ T (strncmp, s, a, 4);
 /* The warning below is not issued because GCC folds strncmp calls with
    the same arguments to zero before it checks for the missing nul.  */
 T (strncmp, a, a, 5);       // { dg-warning "missing terminating nul" "pr92624" { xfail *-*-*} }
-T (strncmp, a, s, 5);       // { dg-warning "missing terminating nul" "strcmp" }
-T (strncmp, s, a, 5);       // { dg-warning "missing terminating nul" "strcmp" }
+T (strncmp, a, s, 5);       // { dg-warning "specified bound 5 exceeds the size 4 of unterminated array" "strcmp" }
+T (strncmp, s, a, 5);       // { dg-warning "specified bound 5 exceeds the size 4 of unterminated array" "strcmp" }
 
 T (strcpy, d, a);           // { dg-warning "missing terminating nul" "strcpy" }
 
@@ -136,10 +143,10 @@ T (strspn, s, a);           // { dg-warning "missing terminating nul" "strcspn"
 T (strdup, a);              // { dg-warning "missing terminating nul" "strdup" }
 
 T (strndup, a, 4);
-T (strndup, a, 5);          // { dg-warning "missing terminating nul" "strndup" }
+T (strndup, a, 5);          // { dg-warning "specified bound 5 exceeds the size 4 of unterminated array" "strndup" }
 T (strndup, b + 3, 2);
 T (strndup, b + 4, 1);
-T (strndup, b + 4, 2);      // { dg-warning "missing terminating nul" "strndup" }
+T (strndup, b + 4, 2);      // { dg-warning "specified bound 2 exceeds the size 1 of unterminated array" "strndup" }
 
 T (strlen, a);              // { dg-warning "missing terminating nul" "strlen" }
 
@@ -161,11 +168,12 @@ T (__stpcpy_chk, d, a, -1);           // { dg-warning "missing terminating nul"
 
 
 T (__stpncpy_chk, d, a, 4, -1);
-T (__stpncpy_chk, d, a, 5, -1);       // { dg-warning "missing terminating nul" "stpncpy_chk" }
+T (__stpncpy_chk, d, a, 5, -1);       // { dg-warning "specified bound 5 exceeds the size 4 of unterminated array" "stpncpy_chk" }
 T (__stpncpy_chk, d, a, n, -1);
 
-T (__stpncpy_chk, d, a + n, 4, -1);
-T (__stpncpy_chk, d, a + n, 5, -1);   // { dg-warning "missing terminating nul" "stpncpy_chk" }
+T (__stpncpy_chk, d, a + n, 3, -1);
+T (__stpncpy_chk, d, a + n, 4, -1);   // { dg-warning "specified bound 4 may exceed the size of at most 4 of unterminated array" "stpncpy_chk" }
+T (__stpncpy_chk, d, a + n, 5, -1);   // { dg-warning "specified bound 5 exceeds the size of at most 4 of unterminated array" "stpncpy_chk" }
 
 T (__stpncpy_chk, d, b, 4, -1);
 T (__stpncpy_chk, d, b, 5, -1);
@@ -180,16 +188,17 @@ T (__stpncpy_chk, d, b + 3, 5, -1);
 T (__stpncpy_chk, d, b + 3, n, -1);
 
 T (__stpncpy_chk, d, b + 4, 1, -1);
-T (__stpncpy_chk, d, b + 4, 2, -1);   // { dg-warning "missing terminating nul" "stpncpy_chk" }
+T (__stpncpy_chk, d, b + 4, 2, -1);   // { dg-warning "specified bound 2 exceeds the size 1 of unterminated array" "stpncpy_chk" }
 T (__stpncpy_chk, d, b + 4, n, -1);
 
 
 T (__strncat_chk, d, a, 4, -1);
-T (__strncat_chk, d, a, 5, -1);       // { dg-warning "missing terminating nul" "strncat_chk" }
+T (__strncat_chk, d, a, 5, -1);       // { dg-warning "specified bound 5 exceeds the size 4 of unterminated array" "strncat_chk" }
 T (__strncat_chk, d, a, n, -1);
 
-T (__strncat_chk, d, a + n, 4, -1);
-T (__strncat_chk, d, a + n, 5, -1);   // { dg-warning "missing terminating nul" "strncat_chk" }
+T (__strncat_chk, d, a + n, 3, -1);
+T (__strncat_chk, d, a + n, 4, -1);   // { dg-warning "specified bound 4 may exceed the size of at most 4 of unterminated array" "strncat_chk" }
+T (__strncat_chk, d, a + n, 5, -1);   // { dg-warning "specified bound 5 exceeds the size of at most 4 of unterminated array" "strncat_chk" }
 
 T (__strncat_chk, d, b, 4, -1);
 T (__strncat_chk, d, b, 5, -1);
@@ -204,16 +213,17 @@ T (__strncat_chk, d, b + 3, 5, -1);
 T (__strncat_chk, d, b + 3, n, -1);
 
 T (__strncat_chk, d, b + 4, 1, -1);
-T (__strncat_chk, d, b + 4, 2, -1);   // { dg-warning "missing terminating nul" "strncat_chk" }
+T (__strncat_chk, d, b + 4, 2, -1);   // { dg-warning "specified bound 2 exceeds the size 1 of unterminated array" "strncat_chk" }
 T (__strncat_chk, d, b + 4, n, -1);
 
 
 T (__strncpy_chk, d, a, 4, -1);
-T (__strncpy_chk, d, a, 5, -1);       // { dg-warning "missing terminating nul" "strncpy_chk" }
+T (__strncpy_chk, d, a, 5, -1);       // { dg-warning "specified bound 5 exceeds the size 4 of unterminated array" "strncpy_chk" }
 T (__strncpy_chk, d, a, n, -1);
 
-T (__strncpy_chk, d, a + n, 4, -1);
-T (__strncpy_chk, d, a + n, 5, -1);   // { dg-warning "missing terminating nul" "strncpy_chk" }
+T (__strncpy_chk, d, a + n, 3, -1);
+T (__strncpy_chk, d, a + n, 4, -1);   // { dg-warning "specified bound 4 may exceed the size of at most 4 of unterminated array" "strncpy_chk" }
+T (__strncpy_chk, d, a + n, 5, -1);   // { dg-warning "specified bound 5 exceeds the size of at most 4 of unterminated array" "strncpy_chk" }
 
 T (__strncpy_chk, d, b, 4, -1);
 T (__strncpy_chk, d, b, 5, -1);
@@ -228,7 +238,7 @@ T (__strncpy_chk, d, b + 3, 5, -1);
 T (__strncpy_chk, d, b + 3, n, -1);
 
 T (__strncpy_chk, d, b + 4, 1, -1);
-T (__strncpy_chk, d, b + 4, 2, -1);   // { dg-warning "missing terminating nul" "strncpy" }
+T (__strncpy_chk, d, b + 4, 2, -1);   // { dg-warning "specified bound 2 exceeds the size 1 of unterminated array" "strncpy" }
 T (__strncpy_chk, d, b + 4, n, -1);
 
 
index cb8aeb9b5d9212bee5d6caece6ed93f3abc75459..d4f7956c42db7f706b871fe5c381e9ad974b2e6c 100644 (file)
@@ -7,7 +7,7 @@ void fcst (char *d)
 {
   char a[2] = "0";
 
-  __builtin_strcpy (d, a + 3);    // { dg-warning "\\\[-W(array-bounds|stringop-overflow)" }
+  __builtin_strcpy (d, a + 3);    // { dg-warning "\\\[-W(array-bounds|stringop-overread)" }
 }
 
 void frng (char *d, int i)
@@ -17,14 +17,14 @@ void frng (char *d, int i)
   if (i < 3)
     i = 3;
 
-  __builtin_strcpy (d, a + i);    // { dg-warning "\\\[-W(array-bounds|stringop-overflow)" }
+  __builtin_strcpy (d, a + i);    // { dg-warning "\\\[-W(array-bounds|stringop-overread)" }
 }
 
 void gcst (char *d)
 {
   char a[2] = "0";
 
-  __builtin_strcpy (d, a + 2);    // { dg-warning "\\\[-W(array-bounds|stringop-overflow)" }
+  __builtin_strcpy (d, a + 2);    // { dg-warning "\\\[-W(array-bounds|stringop-overread)" }
 }
 
 void grng (char *d, int i)
@@ -34,7 +34,7 @@ void grng (char *d, int i)
   if (i < 2)
     i = 2;
 
-  __builtin_strcpy (d, a + i);    // { dg-warning "\\\[-W(array-bounds|stringop-overflow)" }
+  __builtin_strcpy (d, a + i);    // { dg-warning "\\\[-W(array-bounds|stringop-overread)" }
 }
 
 /* { dg-prune-output "-Wuninitialized" } */
index 11db965c7ddcb07d254ea9fff02ee89e4dddac56..2df84b2bbd91138a3d262897e25e5172b7ac4ec4 100644 (file)
@@ -63,10 +63,10 @@ void test_strncpy (void)
 
 char* test_strndup (void)
 {
-  return strndup (s, SIZE_MAX - 5);   /* { dg-warning ".strndup. specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+ \\\[-Wstringop-overflow=\\\]" } */
+  return strndup (s, SIZE_MAX - 5);   /* { dg-warning ".strndup. specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+ \\\[-Wstringop-overread" } */
 }
 
 size_t test_strnlen (void)
 {
-  return strnlen (s, SIZE_MAX - 6);   /* { dg-warning ".strnlen. specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+ \\\[-Wstringop-overflow=\\\]" } */
+  return strnlen (s, SIZE_MAX - 6);   /* { dg-warning ".strnlen. specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+ \\\[-Wstringop-overread" } */
 }
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overread-2.c b/gcc/testsuite/gcc.dg/Wstringop-overread-2.c
new file mode 100644 (file)
index 0000000..16dc06d
--- /dev/null
@@ -0,0 +1,117 @@
+/* Verify -Wstringop-overread is issued for reading more than the maximum
+   object size but not for writing.
+  { dg-do compile }
+  { dg-options "-O2 -Wno-stringop-overflow -ftrack-macro-expansion=0" } */
+
+#define PTRDIFF_MAX   __PTRDIFF_MAX__
+#define SIZE_MAX      __SIZE_MAX__
+
+#define NOIPA         __attribute__ ((noipa))
+
+typedef __SIZE_TYPE__ size_t;
+
+void* memchr (const void*, int, size_t);
+int memcmp (const void*, const void*, size_t);
+void* memcpy (const void*, const void*, size_t);
+
+int strncmp (const char*, const char*, size_t);
+char* strncat (char*, const char*, size_t);
+char* strncpy (char*, const char*, size_t);
+size_t strnlen (const char*, size_t);
+
+void sink (int, ...);
+#define sink(...) sink (0, __VA_ARGS__)
+#define T(exp)   sink (exp)
+
+NOIPA void test_memchr (const void *p, int x)
+{
+  size_t dmax = PTRDIFF_MAX;
+  size_t smax = SIZE_MAX;
+
+  T (memchr (p, x, dmax));
+
+  T (memchr (p, x, dmax + 1));     // { dg-warning "specified bound \[0-9\]+ exceeds maximum object size" }
+  T (memchr (p, x, dmax * 2));     // { dg-warning "specified bound \[0-9\]+ exceeds maximum object size" }
+  T (memchr (p, x, smax));         // { dg-warning "\\\[-Wstringop-overread" }
+}
+
+
+NOIPA void test_memcmp (const void *p, const void *q)
+{
+  size_t dmax = PTRDIFF_MAX;
+  size_t smax = SIZE_MAX;
+
+  T (memcmp (p, q, dmax));
+
+  T (memcmp (p, q, dmax + 1));     // { dg-warning "specified bound \[0-9\]+ exceeds maximum object size" }
+  T (memcmp (p, q, dmax * 2));     // { dg-warning "specified bound \[0-9\]+ exceeds maximum object size" }
+  T (memcmp (p, q, smax));         // { dg-warning "\\\[-Wstringop-overread" }
+}
+
+
+NOIPA void test_memcpy (void *p, const void *q)
+{
+  size_t dmax = PTRDIFF_MAX;
+  size_t smax = SIZE_MAX;
+
+  T (memcpy (p, q, dmax));
+
+  T (memcpy (p, q, dmax + 1));    // -Wstringop-overflow disabled
+  T (memcpy (p, q, dmax * 2));    // ditto
+  T (memcpy (p, q, smax));        // ditto
+}
+
+
+NOIPA void test_strncmp (const char *p, const char *q)
+{
+  size_t dmax = PTRDIFF_MAX;
+  size_t smax = SIZE_MAX;
+
+  T (strncmp (p, q, dmax));
+
+  T (strncmp (p, q, dmax + 1));   // { dg-warning "specified bound \[0-9\]+ exceeds maximum object size" "strncmp" }
+  T (strncmp (p, q, dmax * 2));   // { dg-warning "\\\[-Wstringop-overread" "strncmp" }
+  T (strncmp (p, q, smax));       // { dg-warning "\\\[-Wstringop-overread" "strncmp" }
+}
+
+NOIPA void test_strncat (char *p, const char *q)
+{
+  size_t dmax = PTRDIFF_MAX;
+  size_t smax = SIZE_MAX;
+
+  T (strncat (p, q, dmax));
+
+  T (strncat (p, q, dmax + 1));   // { dg-warning "specified bound \[0-9\]+ exceeds maximum object size" }
+  T (strncat (p, q, dmax * 2));   // { dg-warning "\\\[-Wstringop-overread" }
+  T (strncat (p, q, smax));       // { dg-warning "\\\[-Wstringop-overread" }
+}
+
+NOIPA void test_strncpy (char *p, const char *q)
+{
+#if 0
+  /* Disabled: strncpy calls with an excissve bound trigger both
+     -Wstringop-overflow and, when the former option is disabled,
+     -Wstringop-overread.  The latter should probably not trigger.  */
+
+  size_t dmax = PTRDIFF_MAX;
+  size_t smax = SIZE_MAX;
+
+  T (strncpy (p, q, dmax));
+
+  T (strncpy (p, q, dmax + 1));    // -Wstringop-overflow disabled
+  T (strncpy (p, q, dmax * 2));    // ditto
+  T (strncpy (p, q, smax));        // ditto
+#endif
+}
+
+NOIPA void test_strnlen (const char *p)
+{
+  size_t dmax = PTRDIFF_MAX;
+  size_t smax = SIZE_MAX;
+
+  T (strnlen (p, dmax));
+
+  T (strnlen (p, dmax + 1));      // { dg-warning "specified bound \[0-9\]+ exceeds maximum object size" }
+  T (strnlen (p, dmax * 2));      // { dg-warning "\\\[-Wstringop-overread" }
+  T (strnlen (p, smax));          // { dg-warning "\\\[-Wstringop-overread" }
+}
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overread.c b/gcc/testsuite/gcc.dg/Wstringop-overread.c
new file mode 100644 (file)
index 0000000..0343e43
--- /dev/null
@@ -0,0 +1,716 @@
+/* Verify -Wstringop-overread is issued appropriately.
+  { dg-do compile }
+  { dg-options "-O2 -ftrack-macro-expansion=0" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+// <libint.h> functions.
+
+char* gettext (const char *);
+
+// <stdio.h> functions.
+
+int puts (const char*);
+int puts_unlocked (const char*);
+
+// <string.h> functions.
+
+char* strchr (const char*, int);
+
+int strcmp (const char*, const char*);
+int strncmp (const char*, const char*, size_t);
+
+char* strcat (char*, const char*);
+char* strcpy (char*, const char*);
+char* strncpy (char*, const char*, size_t);
+char* strdup (const char*);
+char* strndup (const char*, size_t);
+
+char* strpbrk (char*, const char*);
+size_t strcspn (const char*, const char*);
+size_t strspn (const char*, const char*);
+char* strstr (char*, const char*);
+
+size_t strlen (const char*);
+size_t strnlen (const char*, size_t);
+
+
+void sink (int, ...);
+#define sink(...) sink (0, __VA_ARGS__)
+
+extern char *d;
+extern char a0[0];              // { dg-message "source object 'a0'" }
+extern char a1[1];              // { dg-message "source object 'a1'" }
+extern char a2[2];              // { dg-message "source object 'a2'" }
+
+extern char b1[1];
+extern char b2[2];
+extern char bx[];
+
+const char s0[0] = { };         // { dg-message "source object 's0'" }
+const char s1[1] = "";          // { dg-message "source object 's1'" }
+const char s2[2] = "1";         // { dg-message "source object 's2'" }
+
+#define T(x) sink (0, (x))
+
+
+void test_strcat_array (const char *s, int i, int i0)
+{
+  if (i0 < 0)
+    i0 = 0;
+
+  T (strcat (d, a0));           // { dg-warning "'strcat' reading 1 or more bytes from a region of size 0" }
+  T (strcat (d, a0 + i));       // { dg-warning "'strcat' reading 1 or more bytes from a region of size 0" }
+  T (strcat (d, a0 + i + 1));   // { dg-warning "'strcat' reading 1 or more bytes from a region of size 0" }
+
+  T (strcat (d, a0 + i0));      // { dg-warning "'strcat' reading 1 or more bytes from a region of size 0" }
+
+  T (strcat (d, a1));
+  T (strcat (d, a1 + 1));       // { dg-warning "'strcat' reading 1 or more bytes from a region of size 0" }
+  T (strcat (d, a1 + i));
+  T (strcat (d, a1 + i + 1));
+
+  T (strcat (d, a1 + i0));
+  T (strcat (d, a1 + i0 + 1));  // { dg-warning "'strcat' reading 1 or more bytes from a region of size 0" }
+
+  T (strcat (d, a2));
+  T (strcat (d, a2 + 1));
+  T (strcat (d, a2 + 2));       // { dg-warning "'strcat' reading 1 or more bytes from a region of size 0" }
+  T (strcat (d, a2 + i));
+  T (strcat (d, a2 + i + 2));
+
+  T (strcat (d, a2 + i0));
+  T (strcat (d, a2 + i0 + 1));
+  T (strcat (d, a2 + i0 + 2));  // { dg-warning "'strcat' reading 1 or more bytes from a region of size 0" }
+
+  // Repeat the above with the arguments reversed.
+
+  T (strcat (a0, s));           // { dg-warning "'strcat' writing 1 or more bytes into a region of size 0" }
+  T (strcat (a0 + i, s));       // { dg-warning "'strcat' writing 1 or more bytes into a region of size 0" }
+  T (strcat (a0 + i + 1, s));   // { dg-warning "'strcat' writing 1 or more bytes into a region of size 0" }
+
+  T (strcat (a0 + i0, s));      // { dg-warning "'strcat' writing 1 or more bytes into a region of size 0" }
+
+  T (strcat (a1, s));
+  T (strcat (a1 + 1, s));       // { dg-warning "'strcat' writing 1 or more bytes into a region of size 0" }
+  T (strcat (a1 + i, s));
+  T (strcat (a1 + i + 1, s));
+
+  T (strcat (a1 + i0, s));
+  T (strcat (a1 + i0 + 1, s));  // { dg-warning "'strcat' writing 1 or more bytes into a region of size 0" }
+
+  T (strcat (a2, s));
+  T (strcat (a2 + 1, s));
+  T (strcat (a2 + 2, s));       // { dg-warning "'strcat' writing 1 or more bytes into a region of size 0" }
+  T (strcat (a2 + i, s));
+  T (strcat (a2 + i + 2, s));
+
+  T (strcat (a2 + i0, s));
+  T (strcat (a2 + i0 + 1, s));
+  T (strcat (a2 + i0 + 2, s));  // { dg-warning "'strcat' writing 1 or more bytes into a region of size 0" }
+}
+
+void test_strcat_literal (int i)
+{
+  T (strcat (d, ""));
+  T (strcat (d, "" + 0));
+  T (strcat (d, "" + i));
+
+  T (strcat (d, "1"));
+  T (strcat (d, "1" + 1));
+  T (strcat (d, "1" + 2));      // { dg-warning "'strcat' reading 1 or more bytes from a region of size 0" }
+  T (strcat (d, "1" + i));
+
+  T (strcat (d, "12"));
+  T (strcat (d, "12" + 1));
+  T (strcat (d, "12" + 2));
+  T (strcat (d, "12" + 3));     // { dg-warning "'strcat' reading 1 or more bytes from a region of size 0" }
+  T (strcat (d, "12" + i));
+}
+
+void test_strcat_string (int i)
+{
+  T (strcat (d, s0));           // { dg-warning "'strcat' reading 1 or more bytes from a region of size 0" }
+  T (strcat (d, s0 + 1));       // { dg-warning "'strcat' reading 1 or more bytes from a region of size 0" }
+  T (strcat (d, s0 + i));       // { dg-warning "'strcat' (reading 1 or more bytes from a region of size 0|argument missing terminating nul)" }
+
+  T (strcat (d, s1));
+  T (strcat (d, s1 + 1));      // { dg-warning "'strcat' reading 1 or more bytes from a region of size 0" }
+  T (strcat (d, s1 + 2));      // { dg-warning "'strcat' reading 1 or more bytes from a region of size 0" }
+  T (strcat (d, s1 + i));
+
+  T (strcat (d, s2));
+  T (strcat (d, s2 + 1));
+  T (strcat (d, s2 + 2));      // { dg-warning "'strcat' reading 1 or more bytes from a region of size 0" }
+  T (strcat (d, s2 + 3));      // { dg-warning "'strcat' reading 1 or more bytes from a region of size 0" }
+  T (strcat (d, s2 + i));
+}
+
+
+void test_strcpy_array (int i, int i0)
+{
+  if (i0 < 0)
+    i0 = 0;
+
+  T (strcpy (d, a0));           // { dg-warning "'strcpy' reading 1 or more bytes from a region of size 0" }
+  T (strcpy (d, a0 + i));       // { dg-warning "'strcpy' reading 1 or more bytes from a region of size 0" }
+  T (strcpy (d, a0 + i + 1));   // { dg-warning "'strcpy' reading 1 or more bytes from a region of size 0" }
+
+  T (strcpy (d, a0 + i0));      // { dg-warning "'strcpy' reading 1 or more bytes from a region of size 0" }
+
+  T (strcpy (d, a1));
+  T (strcpy (d, a1 + 1));       // { dg-warning "'strcpy' reading 1 or more bytes from a region of size 0" }
+  T (strcpy (d, a1 + i));
+  T (strcpy (d, a1 + i + 1));
+
+  T (strcpy (d, a1 + i0));
+  T (strcpy (d, a1 + i0 + 1));  // { dg-warning "'strcpy' reading 1 or more bytes from a region of size 0" }
+
+  T (strcpy (d, a2));
+  T (strcpy (d, a2 + 1));
+  T (strcpy (d, a2 + 2));       // { dg-warning "'strcpy' reading 1 or more bytes from a region of size 0" }
+  T (strcpy (d, a2 + i));
+  T (strcpy (d, a2 + i + 2));
+
+  T (strcpy (d, a2 + i0));
+  T (strcpy (d, a2 + i0 + 1));
+  T (strcpy (d, a2 + i0 + 2));  // { dg-warning "'strcpy' reading 1 or more bytes from a region of size 0" }
+}
+
+void test_strcpy_literal (int i)
+{
+  T (strcpy (d, ""));
+  T (strcpy (d, "" + 0));
+  T (strcpy (d, "" + i));
+
+  T (strcpy (d, "1"));
+  T (strcpy (d, "1" + 1));
+  T (strcpy (d, "1" + 2));      // { dg-warning "'strcpy' reading 1 or more bytes from a region of size 0" }
+  T (strcpy (d, "1" + i));
+
+  T (strcpy (d, "12"));
+  T (strcpy (d, "12" + 1));
+  T (strcpy (d, "12" + 2));
+  T (strcpy (d, "12" + 3));     // { dg-warning "'strcpy' reading 1 or more bytes from a region of size 0" }
+  T (strcpy (d, "12" + i));
+}
+
+void test_strcpy_string (int i)
+{
+  T (strcpy (d, s0));           // { dg-warning "'strcpy' reading 1 or more bytes from a region of size 0" }
+  T (strcpy (d, s0 + 1));       // { dg-warning "'strcpy' reading 1 or more bytes from a region of size 0" }
+  T (strcpy (d, s0 + i));       // { dg-warning "'strcpy' (reading 1 or more bytes from a region of size 0|argument missing terminating nul)" }
+
+  T (strcpy (d, s1));
+  T (strcpy (d, s1 + 1));      // { dg-warning "'strcpy' reading 1 or more bytes from a region of size 0" }
+  T (strcpy (d, s1 + 2));      // { dg-warning "'strcpy' reading 1 or more bytes from a region of size 0" }
+  T (strcpy (d, s1 + i));
+
+  T (strcpy (d, s2));
+  T (strcpy (d, s2 + 1));
+  T (strcpy (d, s2 + 2));      // { dg-warning "'strcpy' reading 1 or more bytes from a region of size 0" }
+  T (strcpy (d, s2 + 3));      // { dg-warning "'strcpy' reading 1 or more bytes from a region of size 0" }
+  T (strcpy (d, s2 + i));
+}
+
+
+void test_strncpy_array (int i)
+{
+  T (strncpy (d, a0, 0));
+  T (strncpy (d, a0, 1));       // { dg-warning "'strncpy' reading 1 byte from a region of size 0" }
+  T (strncpy (d, a0 + i, 0));
+  T (strncpy (d, a0 + i, 1));   // { dg-warning "'strncpy' reading 1 byte from a region of size 0" }
+
+  T (strncpy (d, a1, 0));
+  T (strncpy (d, a1, 1));
+  T (strncpy (d, a1 + 1, 0));
+  T (strncpy (d, a1 + 1, 1));   // { dg-warning "'strncpy' reading 1 byte from a region of size 0" }
+  T (strncpy (d, a1 + i, 0));
+  T (strncpy (d, a1 + i, 1));
+  T (strncpy (d, a1 + i, 2));
+}
+
+
+void test_strncpy_literal (int i, int i0)
+{
+  if (i0 < 0)
+    i0 = 0;
+
+  T (strncpy (d, "", 0));
+  T (strncpy (d, "", 1));
+  T (strncpy (d, "", 2));
+
+  T (strncpy (d, "" + i, 0));
+  T (strncpy (d, "" + i, 1));
+  T (strncpy (d, "" + i0, 1));
+  T (strncpy (d, "" + i0, 1));
+
+  T (strncpy (d, "" + 1, 0));
+  T (strncpy (d, "" + 1, 1));   // { dg-warning "'strncpy' reading 1 byte from a region of size 0" }
+
+  T (strncpy (d, "1", 0));
+  T (strncpy (d, "1" + 1, 0));
+  T (strncpy (d, "1" + 1, 1));
+  T (strncpy (d, "1" + 1, 2));
+  T (strncpy (d, "1" + i, 2));
+
+  T (strncpy (d, "1" + 2, 0));
+  T (strncpy (d, "1" + 2, 1));  // { dg-warning "'strncpy' reading 1 byte from a region of size 0" }
+}
+
+
+void test_strlen_array (int i, int i0)
+{
+  if (i0 < 0)
+    i0 = 0;
+
+  T (strlen (a0));              // { dg-warning "'strlen' reading 1 or more bytes from a region of size 0" }
+  T (strlen (a0 + i));          // { dg-warning "'strlen' reading 1 or more bytes from a region of size 0" }
+  T (strlen (a0 + i + 1));      // { dg-warning "'strlen' reading 1 or more bytes from a region of size 0" }
+
+  T (strlen (a0 + i0));         // { dg-warning "'strlen' reading 1 or more bytes from a region of size 0" }
+
+  T (strlen (a1));
+  T (strlen (a1 + 1));          // { dg-warning "'strlen' reading 1 or more bytes from a region of size 0" }
+  T (strlen (a1 + i));
+  T (strlen (a1 + i + 1));
+
+  T (strlen (a1 + i0));
+  T (strlen (a1 + i0 + 1));     // { dg-warning "'strlen' reading 1 or more bytes from a region of size 0" }
+
+  T (strlen (a2));
+  T (strlen (a2 + 1));
+  T (strlen (a2 + 2));          // { dg-warning "'strlen' reading 1 or more bytes from a region of size 0" }
+  T (strlen (a2 + i));
+  T (strlen (a2 + i + 2));
+
+  T (strlen (a2 + i0));
+  T (strlen (a2 + i0 + 1));
+  T (strlen (a2 + i0 + 2));     // { dg-warning "'strlen' reading 1 or more bytes from a region of size 0" }
+}
+
+
+void test_strnlen_array (int i, int i0, unsigned n)
+{
+  if (i0 < 0)
+    i0 = 0;
+
+  T (strnlen (a0, 0));
+  T (strnlen (a0, 1));          // { dg-warning "'strnlen' (reading 1 byte from a region of size 0|specified bound 1 exceeds source size 0)" }
+  T (strnlen (a0, i0));
+  T (strnlen (a0, i0 + 1));     // { dg-warning "'strnlen' (reading between 1 and \[0-9\]+ bytes from a region of size 0|specified bound \\\[1, \[0-9\]+\\\] exceeds source size 0)" }
+  T (strnlen (a0, n));
+  T (strnlen (a0 + i, 0));
+  T (strnlen (a0 + i, 1));      // { dg-warning "'strnlen' (reading 1 byte from a region of size 0|specified bound 1 exceeds source size 0)" }
+  T (strnlen (a0 + i, i0));
+  T (strnlen (a0 + i, n));
+  T (strnlen (a0 + i + 1, 0));
+  T (strnlen (a0 + i + 1, 1));  // { dg-warning "'strnlen' (reading 1 byte from a region of size 0|specified bound 1 exceeds source size 0)" }
+
+  T (strnlen (a0 + i0, 0));
+  T (strnlen (a0 + i0, 1));     // { dg-warning "'strnlen' (reading 1 byte from a region of size 0|specified bound 1 exceeds source size 0)" }
+  T (strnlen (a0 + i0, n));
+
+  T (strnlen (a1, 0));
+  T (strnlen (a1, 1));
+  T (strnlen (a1, 2));          // { dg-warning "'strnlen' specified bound 2 exceeds source size 1" "pr87492" { xfail *-*-* } }
+  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, 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, n));
+  T (strnlen (a1 + i, 0));
+  T (strnlen (a1 + i, 1));
+  T (strnlen (a1 + i, 2));      // { dg-warning "'strnlen' specified bound 2 exceeds source size 1" }
+  T (strnlen (a1 + i, n));
+  T (strnlen (a1 + i + 1, 0));
+  T (strnlen (a1 + i + 1, 1));
+  T (strnlen (a1 + i + 1, 2));  // { dg-warning "'strnlen' specified bound 2 exceeds source size 1" }
+  T (strnlen (a1 + i + 1, n));
+
+  T (strnlen (a1 + i0, 0));
+  T (strnlen (a1 + i0, 1));
+  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, n));
+
+  T (strnlen (a2, 0));
+  T (strnlen (a2, 1));
+  T (strnlen (a2, 2));
+  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, 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, n));
+  T (strnlen (a2 + i, 0));
+  T (strnlen (a2 + i, 1));
+  T (strnlen (a2 + i, 2));
+  T (strnlen (a2 + i + 2, 0));
+  T (strnlen (a2 + i + 2, 1));
+  T (strnlen (a2 + i + 2, 2));
+  T (strnlen (a2 + i + 2, n));
+
+  T (strnlen (a2 + i0, 0));
+  T (strnlen (a2 + i0, 1));
+  T (strnlen (a2 + i0, 2));
+  T (strnlen (a2 + i0, 3));     // { dg-warning "'strnlen' specified bound 3 exceeds source size 2" }
+  T (strnlen (a2 + i0, n));
+
+  T (strnlen (a2 + i0 + 1, 0));
+  T (strnlen (a2 + i0 + 1, 1));
+  T (strnlen (a2 + i0 + 1, 2));
+  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, 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, n));
+}
+
+
+void test_strcmp_array (const char *s, int i)
+{
+  T (strcmp (a0, ""));        // { dg-warning "'strcmp' reading 1 or more bytes from a region of size 0" "pr?????" { xfail *-*-* } }
+
+  T (strcmp (a0, s));         // { dg-warning "'strcmp' reading 1 or more bytes from a region of size 0" }
+  T (strcmp (a0 + i, s));     // { dg-warning "'strcmp' reading 1 or more bytes from a region of size 0" }
+
+  T (strcmp (a1, s));
+  T (strcmp (a1 + 1, s));     // { dg-warning "'strcmp' reading 1 or more bytes from a region of size 0" }
+  T (strcmp (a1 + i, s));
+  T (strcmp (a1 + i + 1, s));
+
+
+  // Repeat the above with the arguments reversed.
+
+  T (strcmp ("", a0));         // { dg-warning "'strcmp' reading 1 or more bytes from a region of size 0" "pr?????" { xfail *-*-*} }
+
+  T (strcmp (s, a0));         // { dg-warning "'strcmp' reading 1 or more bytes from a region of size 0" }
+  T (strcmp (s, a0 + i));     // { dg-warning "'strcmp' reading 1 or more bytes from a region of size 0" }
+
+  T (strcmp (s, a1));
+  T (strcmp (s, a1 + 1));     // { dg-warning "'strcmp' reading 1 or more bytes from a region of size 0" }
+  T (strcmp (s, a1 + i));
+  T (strcmp (s, a1 + i + 1));
+}
+
+/* The number of characters read is considered to be bounded not just
+   by the third argument to strncmp but also by the length of the shorter
+   of the two strings.  When the string length is unknowm, verify that
+   a warning is only issued for certain reading past the end but not
+   otherwise.  */
+
+void test_strncmp_array (const char *s, int i)
+{
+  T (strncmp (a0, a0, 0));
+
+  T (strncmp (a0, s, 0));
+  T (strncmp (a0, s, 1));       // { dg-warning "'strncmp' reading 1 or more bytes from a region of size 0" "pr?????" { xfail *-*-* } }
+
+  T (strncmp (a0, s, 2));       // { dg-warning "'strncmp' (reading between 1 and 2 bytes from a region of size 0|specified bound 2 exceeds source size 0)" }
+  T (strncmp (a1, s, 0));
+  T (strncmp (a1, s, 1));
+  T (strncmp (a1 + 1, s, 1));   // { dg-warning "'strncmp' reading 1 byte from a region of size 0" "pr?????" { xfail *-*-*} }
+  T (strncmp (a1, s, 1));
+  T (strncmp (a1 + 1, s, 2));   // { dg-warning "'strncmp' (reading between 1 and 2 bytes from a region of size 0|specified bound 2 exceeds source size 0)" }
+
+  T (strncmp (a2, s, 1));
+  T (strncmp (a2, s, 2));
+  T (strncmp (a2, s, 3));
+
+  T (strncmp (a2 + 1, s, 1));
+  T (strncmp (a2 + 2, s, 2));   // { dg-warning "'strncmp' (reading between 1 and 2 bytes from a region of size 0|specified bound 2 exceeds source size 0)" }
+
+  T (strncmp (a1, b1, 0));
+  T (strncmp (a1, b1, 1));
+  T (strncmp (a1, b1, 2));      // { dg-warning "'strncmp' specified bound 2 exceeds source size 1" }
+}
+
+
+void test_strncmp_literal (const char *s, int i)
+{
+  T (strncmp (a0, "", 0));
+  T (strncmp (a0, "1", 0));
+  T (strncmp (a0, "12", 0));
+
+  /* The calls with a bound in excess of the length of the literal are
+     folded early (most into strcmp) so the warning doesn't trigger.  */
+  T (strncmp (s, "", 0));
+
+  T (strncmp (s, "1", 0));
+  T (strncmp (s, "1", 1));
+  T (strncmp (s, "1", 2));      // { dg-warning "\\\[-Wstringop-overread" "pr93665" { xfail *-*-* } }
+
+  T (strncmp (s, "12", 0));
+  T (strncmp (s, "12", 1));
+  T (strncmp (s, "12", 2));
+  T (strncmp (s, "12", 3));     // { dg-warning "\\\[-Wstringop-overread" "pr93665" { xfail *-*-* } }
+
+  T (strncmp (s, "123", 0));
+  T (strncmp (s, "123", 1));
+  T (strncmp (s, "123", 2));
+  T (strncmp (s, "123", 3));
+  T (strncmp (s, "123", 4));    // { dg-warning "\\\[-Wstringop-overread" "pr93665" { xfail *-*-* } }
+}
+
+
+void test_strchr_array (int x, int i)
+{
+  T (strchr (a0, x));         // { dg-warning "'strchr' reading 1 or more bytes from a region of size 0" }
+  T (strchr (a0 + i, x));     // { dg-warning "'strchr' reading 1 or more bytes from a region of size 0" }
+
+  T (strchr (a1, x));
+  T (strchr (a1 + 1, x));     // { dg-warning "'strchr' reading 1 or more bytes from a region of size 0" }
+  T (strchr (a1 + i, x));
+  T (strchr (a1 + i + 1, x));
+}
+
+
+void test_strdup_array (int i)
+{
+  T (strdup (a0));            // { dg-warning "'strdup' reading 1 or more bytes from a region of size 0" }
+  T (strdup (a0 + i));        // { dg-warning "'strdup' reading 1 or more bytes from a region of size 0" }
+
+  T (strdup (a1));
+  T (strdup (a1 + 1));        // { dg-warning "'strdup' reading 1 or more bytes from a region of size 0" }
+  T (strdup (a1 + i));
+  T (strdup (a1 + i + 1));
+}
+
+
+void test_strndup_array (int i, int i0, unsigned n)
+{
+  if (i0 < 0)
+    i0 = 0;
+
+  T (strndup (a0, 0));
+  T (strndup (a0, 1));          // { dg-warning "'strndup' (reading 1 byte from a region of size 0|specified bound 1 exceeds source size 0)" }
+  T (strndup (a0, i0));
+  T (strndup (a0, i0 + 1));     // { dg-warning "'strndup' (reading between 1 and \[0-9\]+ bytes from a region of size 0|specified bound \\\[1, \[0-9\]+\\\] exceeds source size 0)" }
+  T (strndup (a0, n));
+  T (strndup (a0 + i, 0));
+  T (strndup (a0 + i, 1));      // { dg-warning "'strndup' (reading 1 byte from a region of size 0|specified bound 1 exceeds source size 0)" }
+  T (strndup (a0 + i, i0));
+  T (strndup (a0 + i, n));
+  T (strndup (a0 + i + 1, 0));
+  T (strndup (a0 + i + 1, 1));  // { dg-warning "'strndup' (reading 1 byte from a region of size 0|specified bound 1 exceeds source size 0)" }
+
+  T (strndup (a0 + i0, 0));
+  T (strndup (a0 + i0, 1));     // { dg-warning "'strndup' (reading 1 byte from a region of size 0|specified bound 1 exceeds source size 0)" }
+  T (strndup (a0 + i0, n));
+
+  T (strndup (a1, 0));
+  T (strndup (a1, 1));
+  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, 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, n));
+  T (strndup (a1 + i, 0));
+  T (strndup (a1 + i, 1));
+  T (strndup (a1 + i, 2));      // { dg-warning "'strndup' specified bound 2 exceeds source size 1" }
+  T (strndup (a1 + i, n));
+  T (strndup (a1 + i + 1, 0));
+  T (strndup (a1 + i + 1, 1));
+  T (strndup (a1 + i + 1, 2));  // { dg-warning "'strndup' specified bound 2 exceeds source size 1" }
+  T (strndup (a1 + i + 1, n));
+
+  T (strndup (a1 + i0, 0));
+  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, n));
+
+  T (strndup (a2, 0));
+  T (strndup (a2, 1));
+  T (strndup (a2, 2));
+  T (strndup (a2, n));
+  T (strndup (a2 + 1, 0));
+  T (strndup (a2 + 1, 1));
+  T (strndup (a2 + 1, 2));
+  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, n));
+  T (strndup (a2 + i, 0));
+  T (strndup (a2 + i, 1));
+  T (strndup (a2 + i, 2));
+  T (strndup (a2 + i + 2, 0));
+  T (strndup (a2 + i + 2, 1));
+  T (strndup (a2 + i + 2, 2));
+  T (strndup (a2 + i + 2, n));
+
+  T (strndup (a2 + i0, 0));
+  T (strndup (a2 + i0, 1));
+  T (strndup (a2 + i0, 2));
+  T (strndup (a2 + i0, 3));     // { dg-warning "'strndup' specified bound 3 exceeds source size 2" }
+  T (strndup (a2 + i0, n));
+
+  T (strndup (a2 + i0 + 1, 0));
+  T (strndup (a2 + i0 + 1, 1));
+  T (strndup (a2 + i0 + 1, 2));
+  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, 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, n));
+}
+
+
+void test_strpbrk_array (char *s, int i)
+{
+  T (strpbrk (a0, ""));       // { dg-warning "'strpbrk' reading 1 or more bytes from a region of size 0" "pr?????" { xfail *-*-* } }
+
+  T (strpbrk (a0, s));        // { dg-warning "'strpbrk' reading 1 or more bytes from a region of size 0" }
+  T (strpbrk (a0 + i, s));    // { dg-warning "'strpbrk' reading 1 or more bytes from a region of size 0" }
+
+  T (strpbrk (a1, s));
+  T (strpbrk (a1 + 1, s));    // { dg-warning "'strpbrk' reading 1 or more bytes from a region of size 0" }
+  T (strpbrk (a1 + i, s));
+  T (strpbrk (a1 + i + 1, s));
+
+
+  // Repeat the above with the arguments reversed.
+
+  T (strpbrk ("", a0));       // { dg-warning "'strpbrk' reading 1 or more bytes from a region of size 0" }
+
+  T (strpbrk (s, a0));        // { dg-warning "'strpbrk' reading 1 or more bytes from a region of size 0" }
+  T (strpbrk (s, a0 + i));    // { dg-warning "'strpbrk' reading 1 or more bytes from a region of size 0" }
+
+  T (strpbrk (s, a1));
+  T (strpbrk (s, a1 + 1));    // { dg-warning "'strpbrk' reading 1 or more bytes from a region of size 0" }
+  T (strpbrk (s, a1 + i));
+  T (strpbrk (s, a1 + i + 1));
+}
+
+
+void test_strspn_array (const char *s, int i)
+{
+  T (strspn (a0, ""));        // { dg-warning "'strspn' reading 1 or more bytes from a region of size 0" "pr?????" { xfail *-*-* } }
+
+  T (strspn (a0, s));         // { dg-warning "'strspn' reading 1 or more bytes from a region of size 0" }
+  T (strspn (a0 + i, s));     // { dg-warning "'strspn' reading 1 or more bytes from a region of size 0" }
+
+  T (strspn (a1, s));
+  T (strspn (a1 + 1, s));     // { dg-warning "'strspn' reading 1 or more bytes from a region of size 0" }
+  T (strspn (a1 + i, s));
+  T (strspn (a1 + i + 1, s));
+
+
+  // Repeat the above with the arguments reversed.
+
+  T (strspn ("", a0));         // { dg-warning "'strspn' reading 1 or more bytes from a region of size 0" "pr?????" { xfail *-*-*} }
+
+  T (strspn (s, a0));         // { dg-warning "'strspn' reading 1 or more bytes from a region of size 0" }
+  T (strspn (s, a0 + i));     // { dg-warning "'strspn' reading 1 or more bytes from a region of size 0" }
+
+  T (strspn (s, a1));
+  T (strspn (s, a1 + 1));     // { dg-warning "'strspn' reading 1 or more bytes from a region of size 0" }
+  T (strspn (s, a1 + i));
+  T (strspn (s, a1 + i + 1));
+}
+
+
+void test_strcspn_array (const char *s, int i)
+{
+  /* The call below is tranformed to strlen() so the warning references
+     the latter function instead of strcspn.  Avoid testing that aspect.  */
+  T (strcspn (a0, ""));       // { dg-warning "reading 1 or more bytes from a region of size 0" }
+
+  T (strcspn (a0, s));        // { dg-warning "'strcspn' reading 1 or more bytes from a region of size 0" }
+  T (strcspn (a0 + i, s));    // { dg-warning "'strcspn' reading 1 or more bytes from a region of size 0" }
+
+  T (strcspn (a1, s));
+  T (strcspn (a1 + 1, s));    // { dg-warning "'strcspn' reading 1 or more bytes from a region of size 0" }
+  T (strcspn (a1 + i, s));
+  T (strcspn (a1 + i + 1, s));
+
+
+  // Repeat the above with the arguments reversed.
+
+  T (strcspn ("", a0));       // { dg-warning "'strcspn' reading 1 or more bytes from a region of size 0" "pr?????" { xfail *-*-*} }
+
+  T (strcspn (s, a0));        // { dg-warning "'strcspn' reading 1 or more bytes from a region of size 0" }
+  T (strcspn (s, a0 + i));    // { dg-warning "'strcspn' reading 1 or more bytes from a region of size 0" }
+
+  T (strcspn (s, a1));
+  T (strcspn (s, a1 + 1));    // { dg-warning "'strcspn' reading 1 or more bytes from a region of size 0" }
+  T (strcspn (s, a1 + i));
+  T (strcspn (s, a1 + i + 1));
+}
+
+
+void test_strstr_array (char *s, int i)
+{
+  T (strstr (a0, ""));        // { dg-warning "'strstr' reading 1 or more bytes from a region of size 0" "pr?????" { xfail *-*-* } }
+
+  T (strstr (a0, s));         // { dg-warning "'strstr' reading 1 or more bytes from a region of size 0" }
+  T (strstr (a0 + i, s));     // { dg-warning "'strstr' reading 1 or more bytes from a region of size 0" }
+
+  T (strstr (a1, s));
+  T (strstr (a1 + 1, s));     // { dg-warning "'strstr' reading 1 or more bytes from a region of size 0" }
+  T (strstr (a1 + i, s));
+  T (strstr (a1 + i + 1, s));
+
+
+  // Repeat the above with the arguments reversed.
+
+  T (strstr ("", a0));        // { dg-warning "'strstr' reading 1 or more bytes from a region of size 0" }
+
+  T (strstr (s, a0));         // { dg-warning "'strstr' reading 1 or more bytes from a region of size 0" }
+  T (strstr (s, a0 + i));     // { dg-warning "'strstr' reading 1 or more bytes from a region of size 0" }
+
+  T (strstr (s, a1));
+  T (strstr (s, a1 + 1));     // { dg-warning "'strstr' reading 1 or more bytes from a region of size 0" }
+  T (strstr (s, a1 + i));
+  T (strstr (s, a1 + i + 1));
+}
+
+
+void test_puts_array (int i)
+{
+  T (puts (a0));              // { dg-warning "'puts' reading 1 or more bytes from a region of size 0" }
+  T (puts (a0 + i));          // { dg-warning "'puts' reading 1 or more bytes from a region of size 0" }
+
+  T (puts (a1));
+  T (puts (a1 + 1));          // { dg-warning "'puts' reading 1 or more bytes from a region of size 0" }
+  T (puts (a1 + i));
+  T (puts (a1 + i + 1));
+}
+
+
+void test_puts_unlocked_array (int i)
+{
+  T (puts_unlocked (a0));     // { dg-warning "'puts_unlocked' reading 1 or more bytes from a region of size 0" }
+  T (puts_unlocked (a0 + i)); // { dg-warning "'puts_unlocked' reading 1 or more bytes from a region of size 0" }
+
+  T (puts_unlocked (a1));
+  T (puts_unlocked (a1 + 1)); // { dg-warning "'puts_unlocked' reading 1 or more bytes from a region of size 0" }
+  T (puts_unlocked (a1 + i));
+  T (puts_unlocked (a1 + i + 1));
+}
+
+
+void test_gettext_array (int i)
+{
+  T (gettext (a0));           // { dg-warning "'gettext' reading 1 or more bytes from a region of size 0" }
+  T (gettext (a0 + i));       // { dg-warning "'gettext' reading 1 or more bytes from a region of size 0" }
+
+  T (gettext (a1));
+  T (gettext (a1 + 1));       // { dg-warning "'gettext' reading 1 or more bytes from a region of size 0" }
+  T (gettext (a1 + i));
+  T (gettext (a1 + i + 1));
+}
index ef2144d62075fdafbd5568a804e0c45844afa119..ba4757d673fbcd56b4ae2938ba0e481f56cadcb7 100644 (file)
@@ -26,8 +26,8 @@ void test_strnlen_array_cst (void)
   T (strnlen (ns3, 1));
   T (strnlen (ns3, 2));
   T (strnlen (ns3, 3));
-  T (strnlen (ns3, 4));             /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound 4" } */
-  T (strnlen (ns3, DIFF_MAX));      /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound \[0-9\]+" } */
+  T (strnlen (ns3, 4));             /* { dg-warning "specified bound 4 exceeds source size 3" } */
+  T (strnlen (ns3, DIFF_MAX));      /* { dg-warning "specified bound \[0-9\]+ exceeds source size" } */
   T (strnlen (ns3, SIZE_MAX));      /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */
 
   NONSTRING char ns5[5];
@@ -37,8 +37,8 @@ void test_strnlen_array_cst (void)
   T (strnlen (ns5, 1));
   T (strnlen (ns5, 2));
   T (strnlen (ns5, 3));
-  T (strnlen (ns5, 6));             /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound 6" } */
-  T (strnlen (ns5, DIFF_MAX));      /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound \[0-9\]+" } */
+  T (strnlen (ns5, 6));             /* { dg-warning "specified bound 6 exceeds source size 5" } */
+  T (strnlen (ns5, DIFF_MAX));      /* { dg-warning "specified bound \[0-9\]+ exceeds source size 5" } */
   T (strnlen (ns5, SIZE_MAX));      /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */
 }
 
@@ -52,8 +52,8 @@ void test_strnlen_array_range (void)
   T (strnlen (ns3, UR (0, 9)));
   T (strnlen (ns3, UR (3, 4)));
   T (strnlen (ns3, UR (3, DIFF_MAX)));
-  T (strnlen (ns3, UR (4, 5)));     /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound \\\[4, 5]" } */
-  T (strnlen (ns3, UR (DIFF_MAX, SIZE_MAX)));  /* { dg-warning "argument 1 declared attribute .nonstring. is smaller " } */
+  T (strnlen (ns3, UR (4, 5)));     /* { dg-warning "specified bound \\\[4, 5] exceeds source size 3" } */
+  T (strnlen (ns3, UR (DIFF_MAX, SIZE_MAX)));  /* { dg-warning "specified bound \\\[\[0-9\]+, \[0-9\]+] exceeds source size 3 " } */
 }
 
 
@@ -73,8 +73,8 @@ void test_strnlen_string_cst (void)
   T (3, "12",  3, 1);
   T (3, "12",  3, 9);
   T (3, "123", 3, 1);
-  T (3, "123", 3, 4);               /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound 4" } */
-  T (3, "123", 3, 9);               /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound 9" } */
+  T (3, "123", 3, 4);               /* { dg-warning "specified bound 4 exceeds source size 3" } */
+  T (3, "123", 3, 9);               /* { dg-warning "specified bound 9 exceeds source size 3" } */
 
   T (5, "1",   2, 1);
   T (5, "1",   2, 2);
@@ -84,7 +84,7 @@ void test_strnlen_string_cst (void)
   T (5, "12",  3, 9);
   T (5, "123", 3, 1);
   T (5, "123", 3, 5);
-  T (5, "123", 3, 6);               /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound 6" } */
+  T (5, "123", 3, 6);               /* { dg-warning "specified bound 6 exceeds source size 5" } */
 
   /* Strnlen shouldn't trigger a warning for arrays of unknown size
      (except for accesses to uninitialized elements when those are
@@ -110,6 +110,6 @@ void test_strnlen_string_range (void)
 {
   T (3, "1",   2, UR (0, 1));
   T (3, "1",   2, UR (3, 9));
-  T (3, "123", 3, UR (4, 5));       /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound \\\[4, 5]" } */
-  T (3, "123", 3, UR (5, 9));       /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound \\\[5, 9]" } */
+  T (3, "123", 3, UR (4, 5));       /* { dg-warning "specified bound \\\[4, 5] exceeds source size 3" } */
+  T (3, "123", 3, UR (5, 9));       /* { dg-warning "specified bound \\\[5, 9] exceeds source size 3" } */
 }
index 4a1045045550348546b036eaa7fd0979a8d494fd..34f31fb6aa736ac3e02c959549d94837e8981af9 100644 (file)
@@ -37,15 +37,21 @@ void strncmp_cst (void)
   T (STR, /* [] */, STR, /* [] */, n);
   T (STR, /* [] */, STR, /* [] */, n + 1);    /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */
 
+  T (STR, 1, STR, /* [] */, 1);
   T (STR, 1, STR, /* [] */, n);
   T (STR, 2, STR, /* [] */, n + 1);           /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */
 
+  T (STR, /* [] */, STR, 3, 3);
   T (STR, /* [] */, STR, 3, n);
   T (STR, /* [] */, STR, 4, n + 1);           /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */
 
+  T (STR, /* [] */, NS, /* [] */, 3);
   T (STR, /* [] */, NS, /* [] */, n);
   T (STR, /* [] */, NS, /* [] */, n + 1);     /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */
 
+  T (STR, 5, NS, /* [] */, 4);
+  T (STR, 5, NS, /* [] */, 5);
+  T (STR, 5, NS, /* [] */, 6);
   T (STR, 5, NS, /* [] */, n);
   T (STR, 6, NS, /* [] */, n + 1);            /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */
 
@@ -56,19 +62,22 @@ void strncmp_cst (void)
   T (NS, /* [] */, STR, /* [] */, n);
   T (NS, /* [] */, STR, /* [] */, n + 1);     /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */
 
-  T (NS, 9, STR, /* [] */, n);                /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound" } */
+  T (NS, 9, STR, /* [] */, n);                /* { dg-warning "argument 1 declared attribute 'nonstring' is smaller than the specified bound \[0-9\]+" } */
   T (NS, 10, STR, /* [] */, n + 1);           /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */
 
+  T (NS, /* [] */, STR, 11, 11);
   T (NS, /* [] */, STR, 11, n);
   T (NS, /* [] */, STR, 12, n + 1);           /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */
 
   T (NS, /* [] */, NS, /* [] */, n);
   T (NS, /* [] */, NS, /* [] */, n + 1);      /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */
 
-  T (NS, 13, NS, /* [] */, n);                /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound" } */
+  T (NS, 13, NS, /* [] */, 13);
+  T (NS, 13, NS, /* [] */, n);                /* { dg-warning "argument 1 declared attribute 'nonstring' is smaller than the specified bound \[0-9\]+" } */
   T (NS, 14, NS, /* [] */, n + 1);            /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */
 
-  T (NS, /* [] */, NS, 15, n);                /* { dg-warning "argument 2 declared attribute .nonstring. is smaller than the specified bound" } */
+  T (NS, /* [] */, NS, 15, 15);
+  T (NS, /* [] */, NS, 15, 16);               /* { dg-warning "argument 2 declared attribute 'nonstring' is smaller than the specified bound 16" } */
   T (NS, /* [] */, NS, 16, n + 1);            /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */
 }
 
@@ -81,6 +90,7 @@ void strncmp_range (void)
   T (STR, /* [] */, STR, /* [] */, n);
   T (STR, /* [] */, STR, /* [] */, n + 1);    /* { dg-warning "specified bound \\\[\[0-9\]+, \[0-9\]+] exceeds maximum object size \[0-9\]+" } */
 
+  T (STR, 1, STR, /* [] */, 1);
   T (STR, 1, STR, /* [] */, n);
   T (STR, 2, STR, /* [] */, n + 1);           /* { dg-warning "specified bound \\\[\[0-9\]+, \[0-9\]+] exceeds maximum object size \[0-9\]+" } */
 
@@ -93,7 +103,7 @@ void strncmp_range (void)
   T (STR, 5, NS, /* [] */, n);
   T (STR, 6, NS, /* [] */, n + 1);            /* { dg-warning "specified bound \\\[\[0-9\]+, \[0-9\]+] exceeds maximum object size \[0-9\]+" } */
 
-  T (STR, /* [] */, NS, 7, n);                /* { dg-warning "argument 2 declared attribute .nonstring. is smaller than the specified bound" } */
+  T (STR, /* [] */, NS, 7, n);                /* { dg-warning "argument 2 declared attribute 'nonstring' is smaller than the specified bound \\\[\[0-9\]+, \[0-9\]+]" } */
 
   T (STR, /* [] */, NS, 8, n + 1);            /* { dg-warning "specified bound \\\[\[0-9\]+, \[0-9\]+] exceeds maximum object size \[0-9\]+" } */
 
index 7daff9754c720fee7554c1b3d878b9eda373c619..f2416c16e83c6f24345868719df7311698b7f4d9 100644 (file)
@@ -40,7 +40,7 @@ void strnlen_cst (void)
   T (NS, /* [] */, n);
   T (NS, /* [] */, n + 1);     /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */
 
-  T (NS, 9, n);                /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound" } */
+  T (NS, 9, n);                /* { dg-warning "specified bound \[0-9\]+ exceeds source size 9" } */
   T (NS, 10, n + 1);           /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */
 }
 
@@ -53,12 +53,12 @@ void strnlen_range (void)
   T (STR, /* [] */, n);
   T (STR, /* [] */, n + 1);    /* { dg-warning "specified bound \\\[\[0-9\]+, \[0-9\]+] exceeds maximum object size \[0-9\]+" } */
 
-  T (STR, 1, n);
+  T (STR, 1, n);               /* { dg-warning "specified bound \\\[\[0-9\]+, \[0-9\]+] exceeds source size 1" } */
   T (STR, 2, n + 1);           /* { dg-warning "specified bound \\\[\[0-9\]+, \[0-9\]+] exceeds maximum object size \[0-9\]+" } */
 
   T (NS, /* [] */, n);
   T (NS, /* [] */, n + 1);     /* { dg-warning "specified bound \\\[\[0-9\]+, \[0-9\]+] exceeds maximum object size \[0-9\]+" } */
 
-  T (NS, 9, n);                /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound" } */
+  T (NS, 9, n);                /* { dg-warning "specified bound \\\[\[0-9\]+, \[0-9\]+] exceeds source size 9" } */
   T (NS, 10, n + 1);           /* { dg-warning "specified bound \\\[\[0-9\]+, \[0-9\]+] exceeds maximum object size \[0-9\]+" } */
 }
index 46f5c0d7c59e0e5cf2b22d38f579475f64d55d8a..d93e93ca6766055646b8764fe7ba70dbd133f0e4 100644 (file)
@@ -44,80 +44,80 @@ int strcmp_nonstring_1 (NONSTRING const char *a, const char *b)
      no good on its own.  Use dg-regexp instead to verify that just
      one instance of the warning is issued.  See gcc.dg/pr64223-1
      for a different approach.  */
-  return strcmp (a, b);  /* { dg-regexp "\[^\n\r\]+: warning: .strcmp. argument 1 declared attribute .nonstring. \\\[-Wstringop-overflow=]" "strcmp" } */
+  return strcmp (a, b);  /* { dg-regexp "\[^\n\r\]+: warning: .strcmp. argument 1 declared attribute .nonstring. \\\[-Wstringop-overread\[^\n\r\]*" "strcmp" } */
 }
 
 int strcmp_nonstring_2 (const char *a, NONSTRING const char *b)
 {
-  return strcmp (a, b);  /* { dg-regexp "\[^\n\r\]+: warning: .strcmp. argument 2 declared attribute .nonstring. \\\[-Wstringop-overflow=]" "strcmp" } */
+  return strcmp (a, b);  /* { dg-regexp "\[^\n\r\]+: warning: .strcmp. argument 2 declared attribute .nonstring. \\\[-Wstringop-overread\[^\n\r\]*" "strcmp" } */
 }
 
 int strncmp_nonstring_1 (const char *s)
 {
-  return strncmp (s, ns5, sizeof ns5 + 1);  /* { dg-regexp "\[^\n\r\]+: warning: .strncmp. argument 2 declared attribute .nonstring. \[^\n\r\]+ \\\[-Wstringop-overflow=]" "strncmp" } */
+  return strncmp (s, ns5, sizeof ns5 + 1);  /* { dg-regexp "\[^\n\r\]+: warning: .strncmp. argument 2 declared attribute .nonstring. \[^\n\r\]+ \\\[-Wstringop-overread\[^\n\r\]*" "strncmp" } */
 }
 
 int strncmp_nonstring_2 (const char *s)
 {
-  return strncmp (ns5, s, sizeof ns5 + 1);  /* { dg-regexp "\[^\n\r\]+: warning: .strncmp. argument 1 declared attribute .nonstring. \[^\n\r\]+ \\\[-Wstringop-overflow=]" "strncmp" } */
+  return strncmp (ns5, s, sizeof ns5 + 1);  /* { dg-regexp "\[^\n\r\]+: warning: .strncmp. argument 1 declared attribute .nonstring. \[^\n\r\]+ \\\[-Wstringop-overread\[^\n\r\]*" "strncmp" } */
 }
 
 char* stpcpy_nonstring (char *d, NONSTRING const char *s)
 {
-  return stpcpy (d, s);  /* { dg-regexp "\[^\n\r\]+: warning: .stpcpy. argument 2 declared attribute .nonstring. \\\[-Wstringop-overflow=]" "stpcpy" } */
+  return stpcpy (d, s);  /* { dg-regexp "\[^\n\r\]+: warning: .stpcpy. argument 2 declared attribute .nonstring. \\\[-Wstringop-overread\[^\n\r\]*" "stpcpy" } */
 }
 
 char* stpncpy_nonstring (char *d)
 {
-  return stpncpy (d, ns5, sizeof ns5 + 1);  /* { dg-regexp "\[^\n\r\]+: warning: .stpncpy. argument 2 declared attribute .nonstring. \[^\n\r\]+ \\\[-Wstringop-overflow=]" "stpncpy" } */
+  return stpncpy (d, ns5, sizeof ns5 + 1);  /* { dg-regexp "\[^\n\r\]+: warning: .stpncpy. argument 2 declared attribute .nonstring. \[^\n\r\]+ \\\[-Wstringop-overread\[^\n\r\]*" "stpncpy" } */
 }
 
 char* strchr_nonstring (NONSTRING const char *s, int c)
 {
-  return strchr (s, c);  /* { dg-regexp "\[^\n\r\]+: warning: .strchr. argument 1 declared attribute .nonstring. \\\[-Wstringop-overflow=]" "strchr" } */
+  return strchr (s, c);  /* { dg-regexp "\[^\n\r\]+: warning: .strchr. argument 1 declared attribute .nonstring. \\\[-Wstringop-overread\[^\n\r\]*" "strchr" } */
 }
 
 char* strrchr_nonstring (NONSTRING const char *s, int c)
 {
-  return strrchr (s, c);  /* { dg-regexp "\[^\n\r\]+: warning: .strrchr. argument 1 declared attribute .nonstring. \\\[-Wstringop-overflow=]" "strrchr" } */
+  return strrchr (s, c);  /* { dg-regexp "\[^\n\r\]+: warning: .strrchr. argument 1 declared attribute .nonstring. \\\[-Wstringop-overread\[^\n\r\]*" "strrchr" } */
 }
 
 char* strcpy_nonstring (char *d, NONSTRING const char *s)
 {
-  return strcpy (d, s);  /* { dg-regexp "\[^\n\r\]+: warning: .strcpy. argument 2 declared attribute .nonstring. \\\[-Wstringop-overflow=]" "strcpy" } */
+  return strcpy (d, s);  /* { dg-regexp "\[^\n\r\]+: warning: .strcpy. argument 2 declared attribute .nonstring. \\\[-Wstringop-overread\[^\n\r\]*" "strcpy" } */
 }
 
 char* strncpy_nonstring (char *d)
 {
-  return strncpy (d, ns5, sizeof ns5 + 1);  /* { dg-regexp "\[^\n\r\]+: warning: .strncpy. argument 2 declared attribute .nonstring. \[^\n\r\]+ \\\[-Wstringop-overflow=]" "strncpy" } */
+  return strncpy (d, ns5, sizeof ns5 + 1);  /* { dg-regexp "\[^\n\r\]+: warning: .strncpy. argument 2 declared attribute .nonstring. \[^\n\r\]+ \\\[-Wstringop-overread\[^\n\r\]*" "strncpy" } */
 }
 
 char* strstr_nonstring_1 (NONSTRING const char *a, const char *b)
 {
-  return strstr (a, b);  /* { dg-regexp "\[^\n\r\]+: warning: .strstr. argument 1 declared attribute .nonstring. \\\[-Wstringop-overflow=]" "strstr" } */
+  return strstr (a, b);  /* { dg-regexp "\[^\n\r\]+: warning: .strstr. argument 1 declared attribute .nonstring. \\\[-Wstringop-overread\[^\n\r\]*" "strstr" } */
 }
 
 char* strstr_nonstring_2 (const char *a, NONSTRING const char *b)
 {
-  return strstr (a, b);  /* { dg-regexp "\[^\n\r\]+: warning: .strstr. argument 2 declared attribute .nonstring. \\\[-Wstringop-overflow=]" "strstr" } */
+  return strstr (a, b);  /* { dg-regexp "\[^\n\r\]+: warning: .strstr. argument 2 declared attribute .nonstring. \\\[-Wstringop-overread\[^\n\r\]*" "strstr" } */
 }
 
 char* stdup_nonstring (NONSTRING const char *s)
 {
-  return strdup (s);  /* { dg-regexp "\[^\n\r\]+: warning: .strdup. argument 1 declared attribute .nonstring. \\\[-Wstringop-overflow=]" "strdup" } */
+  return strdup (s);  /* { dg-regexp "\[^\n\r\]+: warning: .strdup. argument 1 declared attribute .nonstring. \\\[-Wstringop-overread\[^\n\r\]*" "strdup" } */
 }
 
 size_t strlen_nonstring (NONSTRING const char *s)
 {
-  return strlen (s);  /* { dg-regexp "\[^\n\r\]+: warning: .strlen. argument 1 declared attribute .nonstring. \\\[-Wstringop-overflow=]" "strlen" } */
+  return strlen (s);  /* { dg-regexp "\[^\n\r\]+: warning: .strlen. argument 1 declared attribute .nonstring. \\\[-Wstringop-overread\[^\n\r\]*" "strlen" } */
 }
 
 int printf_nonstring (NONSTRING const char *s)
 {
-  return printf (s);  /* { dg-regexp "\[^\n\r\]+: warning: .printf. argument 1 declared attribute .nonstring. \\\[-Wstringop-overflow=]" "printf" } */
+  return printf (s);  /* { dg-regexp "\[^\n\r\]+: warning: .printf. argument 1 declared attribute .nonstring. \\\[-Wstringop-overread\[^\n\r\]*" "printf" } */
 }
 
 int sprintf_nonstring_2 (char *d, NONSTRING const char *s)
 {
-  return sprintf (d, s);  /* { dg-regexp "\[^\n\r\]+: warning: .sprintf. argument 2 declared attribute .nonstring. \\\[-Wstringop-overflow=]" "sprintf" } */
+  return sprintf (d, s);  /* { dg-regexp "\[^\n\r\]+: warning: .sprintf. argument 2 declared attribute .nonstring. \\\[-Wstringop-overread\[^\n\r\]*" "sprintf" } */
 }
index b07629dad11b87b777ff8108a66cd878294d7340..7d5b03b9c270f09fa90d39453b9144fcf9b95c14 100644 (file)
@@ -87,7 +87,7 @@ void test_memop_warn_local (const void *src)
   memset (&b->d, 0, offsetfrom (struct B, b, d) + 1);   /* { dg-warning "writing 6 bytes into a region of size 5" } */
   escape (b);
 
-  /* Same as above but clearing just elements of the second element
+  /* Same as above but clearing just members of the second element
      of the array.  */
   memset (&b[1].a.b, 0, offsetfrom (struct B, b[1], a.b) + 1);   /* { dg-warning "writing 4 bytes into a region of size 3" } */
   escape (b);
index 12d2491b9f5b53e46a34bd5a700d297df7f8d616..f2e9c481172f8168cfeb4cab9e5202a3f6a816eb 100644 (file)
@@ -1,6 +1,6 @@
-/* Test exercising -Wstringop-overflow warnings for reading past the end.  */
+/* Test exercising -Wstringop-overread warnings for reading past the end.  */
 /* { dg-do compile } */
-/* { dg-options "-O2 -Wstringop-overflow=1 -ftrack-macro-expansion=0" } */
+/* { dg-options "-O2 -Wstringop-overread -ftrack-macro-expansion=0" } */
 
 #define PTRDIFF_MAX   __PTRDIFF_MAX__
 #define SIZE_MAX      __SIZE_MAX__
@@ -73,22 +73,22 @@ void test_memop_warn_local (void *p, const void *q)
 
   /* Verify memchr/memcmp.  */
   int i = R (0, 255);
-  memchr ("", i, 2);   /* { dg-warning "reading 2 bytes from a region of size 1" } */
-  memchr ("", i, 2);   /* { dg-warning "reading 2 bytes from a region of size 1" } */
-  memchr ("123", i, 5);   /* { dg-warning "reading 5 bytes from a region of size 4" } */
-  memchr (a, i, sizeof a + 1);   /* { dg-warning "reading 5 bytes from a region of size 4" } */
+  memchr ("", i, 2);   /* { dg-warning "specified bound 2 exceeds source size 1" "memchr" } */
+  memchr ("", i, 2);   /* { dg-warning "specified bound 2 exceeds source size 1" "memchr" } */
+  memchr ("123", i, 5);   /* { dg-warning "specified bound 5 exceeds source size 4" "memchr" } */
+  memchr (a, i, sizeof a + 1);   /* { dg-warning "specified bound 5 exceeds source size 4" "memchr" } */
 
-  memcmp (p, "", 2);   /* { dg-warning "reading 2 bytes from a region of size 1" } */
-  memcmp (p, "123", 5);   /* { dg-warning "reading 5 bytes from a region of size 4" } */
-  memcmp (p, a, sizeof a + 1);   /* { dg-warning "reading 5 bytes from a region of size 4" } */
+  memcmp (p, "", 2);   /* { dg-warning "specified bound 2 exceeds source size 1" "memcmp" } */
+  memcmp (p, "123", 5);   /* { dg-warning "specified bound 5 exceeds source size 4" "memcmp" } */
+  memcmp (p, a, sizeof a + 1);   /* { dg-warning "specified bound 5 exceeds source size 4" "memcmp" } */
 
   size_t n = PTRDIFF_MAX + (size_t)1;
-  memchr (p, 1, n);   /* { dg-warning "exceeds maximum object size" } */
-  memcmp (p, q, n);   /* { dg-warning "exceeds maximum object size" } */
+  memchr (p, 1, n);   /* { dg-warning "exceeds maximum object size" "memchr" } */
+  memcmp (p, q, n);   /* { dg-warning "exceeds maximum object size" "memcmp" } */
 
   n = SIZE_MAX;
-  memchr (p, 1, n);   /* { dg-warning "exceeds maximum object size" } */
-  memcmp (p, q, n);   /* { dg-warning "exceeds maximum object size" } */
+  memchr (p, 1, n);   /* { dg-warning "exceeds maximum object size" "memchr" } */
+  memcmp (p, q, n);   /* { dg-warning "exceeds maximum object size" "memcmp" } */
 }
 
 /* Verify that reading beyond the end of a dynamically allocated array
@@ -117,8 +117,8 @@ void test_memop_warn_alloc (void *p)
   /* Verify memchr/memcmp.  */
   n = sizeof *b * 2 + 1;
 
-  memchr (b, 1, n);   /* { dg-warning "reading 9 bytes from a region of size 8" "memcmp from allocated" } */
-  memcmp (p, b, n);   /* { dg-warning "reading 9 bytes from a region of size 8" "memcmp from allocated" } */
+  memchr (b, 1, n);   /* { dg-warning "specified bound 9 exceeds source size 8" "memchr from allocated" } */
+  memcmp (p, b, n);   /* { dg-warning "specified bound 9 exceeds source size 8" "memcmp from allocated" } */
 }
 
 
index 51b425480718ed682bd745344468b400791e027d..a9a617cde23908f5672e889faefbe3a7858e3890 100644 (file)
@@ -12,4 +12,5 @@ void foo(void)
  __builtin_aligned_alloc (10, 16); /* { dg-warning "ignoring return value of '__builtin_aligned_alloc' declared with attribute 'warn_unused_result'" } */
  __builtin_strdup ("pes"); /* { dg-warning "ignoring return value of '__builtin_strdup' declared with attribute 'warn_unused_result'" } */
  __builtin_strndup ("pes", 10); /* { dg-warning "ignoring return value of '__builtin_strndup' declared with attribute 'warn_unused_result'" } */
+ /* { dg-warning "\\\[-Wstringop-overread" "strndup excessive bound" { target *-*-* } .-1 } */
 }
index 23119edf16c815bff8982bfd450181bf57b06849..3f5d935d712de229f5760a5d210810ecd08ea535 100644 (file)
@@ -84,5 +84,5 @@ char* test_strncat (int i)
 {
   const char *s = i < 0 ? "123" : "4567";
 
-  return strncat (d, s, range ());   /* { dg-warning ".__builtin_strncat. specified bound between 4 and \[0-9\]+" } */
+  return strncat (d, s, range ());   /* { dg-warning ".__builtin_strncat. specified bound \\\[4, \[0-9\]+] exceeds destination size 3" } */
 }
index 94fda596901fbb516d7852e496cda4ab4b95e9c4..d7f94ac4d528b32db9ab628f555252d0e4fbb820 100644 (file)
@@ -3,7 +3,7 @@
    when the pointer pointed to by the enclosing object references an object
    sufficiently large to store a string of equal length.
   { dg-do compile }
-  { dg-options "-O2 -Wall -Wextra -fdump-tree-optimized" } */
+  { dg-options "-O2 -Wall -Wextra -Wno-stringop-overread -fdump-tree-optimized" } */
 
 void init (void*);
 
index b7212bcf7957da946b3ea6add25e8d9c50c72d86..2f67babec882aafcc8d4ab55aa8bf03f6b8ecfa8 100644 (file)
@@ -21,9 +21,9 @@ void test_var_flexarray_cst_off (void)
 {
   /* Use arbitrary constants greater than 16 in case GCC ever starts
      unrolling strlen() calls with small array arguments.  */
-  a[0] = 17 < strlen (a0.a + 1);        // { dg-warning "\\\[-Warray-bounds" }
-  a[1] = 19 < strlen (a1.a + 1);
-  a[2] = 23 < strlen (a9.a + 9);
+  a[0] = 17 < strlen (a0.a + 1);        // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
+  a[1] = 19 < strlen (a1.a + 1);        // { dg-warning "\\\[-Wstringop-overread" }
+  a[2] = 23 < strlen (a9.a + 9);        // { dg-warning "\\\[-Wstringop-overread" }
   a[3] = 29 < strlen (ax.a + 3);
 }
 
index 11367d1ec7afbc9d0ee373bb7a489450bc86f099..12e6f255bf5270126589c45856060cc2a3b06d76 100644 (file)
@@ -1,6 +1,6 @@
 /* Test -Wsizeof-pointer-memaccess warnings.  */
 /* { dg-do compile } */
-/* { dg-options "-Wall -Wno-array-bounds -Wno-sizeof-array-argument -Wno-stringop-overflow -Wno-stringop-truncation" } */
+/* { dg-options "-Wall -Wno-array-bounds -Wno-sizeof-array-argument -Wno-stringop-overflow -Wno-stringop-overread -Wno-stringop-truncation" } */
 /* Test just twice, once with -O0 non-fortified, once with -O2 fortified.  */
 /* { dg-skip-if "" { *-*-* }  { "*" } { "-O0" "-O2" } } */
 /* { dg-skip-if "" { *-*-* }  { "-flto" } { "" } } */
index 0912b687e13f104755f1a56386cca68bd6cd0882..3946a8ca18c0ee678a6681090a7d377b7ad53970 100644 (file)
@@ -14,13 +14,13 @@ main (void)
   /* MEMCHR.  */
   if (__builtin_memchr ("", 'x', 1000)) /* Not folded away.  */
     {
-      /* { dg-warning "reading 1000 bytes from a region of size 1" "" { target *-*-* } .-2 } */
+      /* { dg-warning "\\\[-Wstringop-overread" "" { target *-*-* } .-2 } */
       __builtin_abort ();
     }
 
   if (__builtin_memchr (foo1, 'x', 1000)) /* Not folded away.  */
     {
-      /* { dg-warning "reading 1000 bytes from a region of size 1" "" { target *-*-* } .-2 } */
+      /* { dg-warning "\\\[-Wstringop-overread" "" { target *-*-* } .-2 } */
       __builtin_abort ();
     }
 
index a45f18dd6ce1d3eb8d5849d356883a5494eb8551..732d33e006ddf42eb1b186d18a98856b9bee4492 100644 (file)
@@ -27,7 +27,7 @@ void nowarn_scalar_plus_fpri (void)
   int i;
   /* This gets a -Wstringop-overflow for reading past the end but not
      -Wuninitialized because there's nothing to initialize there.  */
-  fpri (&i + 1);              // { dg-warning "\\\[-Wstringop-overflow" }
+  fpri (&i + 1);              // { dg-warning "\\\[-Wstringop-overread" }
 }
 
 void nowarn_array_assign_fpcri (void)
index e91e8cef7512d470042ceda04f95a1cf23a730b1..76180a3f5da8e0cb0ded6bdbac521be9b2a74d26 100644 (file)
@@ -62,5 +62,11 @@ void test (int n0)
 
   int n = n0 < n1 ? n1 : n0;
 
-  sink (strnlen (c + n, n + 1));    /* { dg-warning "specified bound \\\[5, \[0-9\]+] may exceed the size of at most 4 of unterminated array" } */
+  /* N is at least 4 and c[4] is out-of-bounds.  This could trigger
+     either -Warray-bounds or -Wstringop-overread.  -Warray-bounds
+     only diagnoses past-the-end accesses by modifying functions
+     (in gimple-ssa-warn-restrict.c) and even for those, either
+     -Wstringop-overflow or -Wstringop-overread would be more
+     appropriate.  */
+  sink (strnlen (c + n, n + 1));    /* { dg-warning "specified bound \\\[5, \[0-9\]+] exceeds the size of at most 4 of unterminated array" } */
 }
index 09a527ea337365d49e5f30215c39af228d1f167f..02f6f3d5342c2fda4db32378fe2f6b6e7640238a 100644 (file)
@@ -35,7 +35,7 @@ T (&a[1], asz - 1);
 T (&a[v0], asz);               /* { dg-warning "specified bound 5 may exceed the size of at most 5 of unterminated array" } */
 T (&a[v0] + 1, asz);           /* { dg-warning "specified bound 5 may exceed the size of at most 5 of unterminated array" } */
 
-T (a, asz + 1);                /* { dg-warning "specified bound 6 exceeds the size 5 " } */
+T (a, asz + 1);                /* { dg-warning "specified bound 6 exceeds the size 5 of unterminated array" } */
 T (&a[0], asz + 1);            /* { dg-warning "unterminated" } */
 T (&a[0] + 1, asz - 1);
 T (&a[0] + 1, asz + 1);        /* { dg-warning "unterminated" } */
@@ -110,7 +110,7 @@ T (&b[3][1] + i1, bsz);           /* { dg-warning "unterminated" } */
 T (&b[3][1] + i1, bsz - i1);      /* { dg-warning "unterminated" } */
 T (&b[3][1] + i1, bsz - i2);
 T (&b[3][v0], bsz);
-T (&b[3][1] + v0, bsz);           /* { dg-warning "specified bound 5 may exceed the size of at most 4 of unterminated array" } */
+T (&b[3][1] + v0, bsz);           /* { dg-warning "specified bound 5 exceeds the size of at most 4 of unterminated array" } */
 T (&b[3][v0] + v1, bsz);          /* { dg-warning "specified bound 5 may exceed the size of at most 4 of unterminated array" "pr?????" { xfail *-*-* } } */
 
 T (&b[3][1], bsz + 1);            /* { dg-warning "unterminated" } */
@@ -124,7 +124,7 @@ T (&b[i3][i1], bsz);              /* { dg-warning "unterminated" } */
 T (&b[i3][i1] + 1, bsz);          /* { dg-warning "unterminated" } */
 T (&b[i3][i1] + i1, bsz);         /* { dg-warning "specified bound 5 exceeds the size 3 of unterminated array" } */
 T (&b[i3][v0], bsz);
-T (&b[i3][i1] + v0, bsz);         /* { dg-warning "specified bound 5 may exceed the size of at most 4 of unterminated array" } */
+T (&b[i3][i1] + v0, bsz);         /* { dg-warning "specified bound 5 exceeds the size of at most 4 of unterminated array" } */
 T (&b[i3][v0] + v1, bsz);
 
 T (&b[i3][i1], bsz + 1);          /* { dg-warning "unterminated" } */
@@ -212,10 +212,10 @@ T (&s.a[i1] + v0, asz);
 T (s.a, asz + 1);
 T (&s.a[0], asz + 1);
 T (&s.a[0] + 1, asz + 1);
-T (&s.a[0] + v0, asz + 1);
+T (&s.a[0] + v0, asz + 1);        /* { dg-warning "specified bound 6 exceeds source size 5 " } */
 T (&s.a[1], asz + 1);
 T (&s.a[1] + 1, asz + 1);
-T (&s.a[1] + v0, asz + 1);
+T (&s.a[1] + v0, asz + 1);        /* { dg-bogus "specified bound 6 exceeds source size 5" "pr95794" { xfail *-*-* } } */
 
 T (&s.a[i0], asz + 1);
 T (&s.a[i0] + i1, asz + 1);
@@ -266,10 +266,10 @@ const struct B ba[] = {
 T (ba[0].a[0].a, asz + 1);
 T (&ba[0].a[0].a[0], asz + 1);
 T (&ba[0].a[0].a[0] + 1, asz + 1);
-T (&ba[0].a[0].a[0] + v0, asz + 1);
+T (&ba[0].a[0].a[0] + v0, asz + 1);   /* { dg-bogus "specified bound 6 exceeds source size 5" pr95794" { xfail *-*-* } } */
 T (&ba[0].a[0].a[1], asz + 1);
 T (&ba[0].a[0].a[1] + 1, asz + 1);
-T (&ba[0].a[0].a[1] + v0, asz + 1);
+T (&ba[0].a[0].a[1] + v0, asz + 1);   /* { dg-bogus "specified bound 6 exceeds source size 5" pr95794" { xfail *-*-* } } */
 
 T (ba[0].a[0].b, bsz);
 T (&ba[0].a[0].b[0], bsz);
@@ -302,10 +302,10 @@ T (&ba[0].a[1].a[1] + v0, asz + 1);   /* { dg-warning "unterminated" } */
 T (ba[0].a[1].b, bsz + 1);
 T (&ba[0].a[1].b[0], bsz + 1);
 T (&ba[0].a[1].b[0] + 1, bsz + 1);
-T (&ba[0].a[1].b[0] + v0, bsz + 1);
+T (&ba[0].a[1].b[0] + v0, bsz + 1);   /* { dg-bogus "specified bound 6 exceeds source size 5" pr95794" { xfail *-*-* } } */
 T (&ba[0].a[1].b[1], bsz + 1);
 T (&ba[0].a[1].b[1] + 1, bsz + 1);
-T (&ba[0].a[1].b[1] + v0, bsz + 1);
+T (&ba[0].a[1].b[1] + v0, bsz + 1);   /* { dg-bogus "specified bound 6 exceeds source size 5" pr95794" { xfail *-*-* } } */
 
 T (ba[1].a[0].a, asz);
 T (&ba[1].a[0].a[0], asz);
index 4c6de02824f44ba79765c2f05621ed57860465b2..d73086646dc9b994b077e4f705153c7faf376b30 100644 (file)
@@ -1,7 +1,7 @@
-/* When the specified length exceeds one of the arguments of the call to memcmp, 
+/* When the specified length exceeds one of the arguments of the call to memcmp,
    the call to memcmp should NOT be inlined.  */
 /* { dg-do compile } */
-/* { dg-options "-O2 -Wno-stringop-overflow" } */
+/* { dg-options "-O2 -Wno-stringop-overread" } */
 
 typedef struct { char s[8]; int x; } S;
 
@@ -9,7 +9,7 @@ __attribute__ ((noinline)) int
 f1 (S * s)
 {
   int result = 0;
-  result += __builtin_memcmp (s->s, "a", 3); 
+  result += __builtin_memcmp (s->s, "a", 3);
   return result;
 }
 
@@ -17,7 +17,7 @@ __attribute__ ((noinline)) int
 f2 (char *p)
 {
   int result = 0;
-  result += __builtin_memcmp (p, "a", 3); 
+  result += __builtin_memcmp (p, "a", 3);
   return result;
 }
 
index 2f0ff724cde5c1e5940b21336295b81bf5d73794..7eddca397b3a43e7f1b78ffe820f90c8150db688 100644 (file)
@@ -489,10 +489,10 @@ maybe_warn_pass_by_reference (gimple *stmt, wlimits &wlims)
       attr_access *access = rdwr_idx.get (argno - 1);
       if (access)
        {
-         if (access->mode == attr_access::none
-             || access->mode == attr_access::write_only)
+         if (access->mode == access_none
+             || access->mode == access_write_only)
            continue;
-         if (save_always_executed && access->mode == attr_access::read_only)
+         if (save_always_executed && access->mode == access_read_only)
            /* Attribute read_only arguments imply read access.  */
            wlims.always_executed = true;
          else
@@ -524,7 +524,7 @@ maybe_warn_pass_by_reference (gimple *stmt, wlimits &wlims)
 
       if (access)
        {
-         const char* const mode = (access->mode == attr_access::read_only
+         const char* const mode = (access->mode == access_read_only
                                    ? "read_only" : "read_write");
          char attrstr[80];
          int n = sprintf (attrstr, "access (%s, %u", mode, argno);
index 22dd4ac0f3c0440f6700b54fe06c385d3b57a1a9..910f4aa54066c70ac1abb3f9fe070546547cd512 100644 (file)
@@ -5340,6 +5340,15 @@ canonical_type_used_p (const_tree t)
           || TREE_CODE (t) == VECTOR_TYPE);
 }
 
+/* Kinds of access to pass-by-reference arguments to functions.  */
+enum access_mode
+{
+  access_none = 0,
+  access_read_only = 1,
+  access_write_only = 2,
+  access_read_write = access_read_only | access_write_only
+};
+
 #define tree_map_eq tree_map_base_eq
 extern unsigned int tree_map_hash (const void *);
 #define tree_map_marked_p tree_map_base_marked_p