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 ();
}
unsigned sizarg;
/* The access mode. */
- enum access_mode { none, read_only, write_only, read_write };
access_mode mode;
};
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);
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;
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
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;
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;
}
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
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);
/* 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);
/* 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
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 = { };
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;
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;
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;
{
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));
{
/* 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));
{
/* 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;
}
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;
else
loc = DECL_SOURCE_LOCATION (ref.ref);
- if (write)
+ if (mode == access_read_write || mode == access_write_only)
{
if (DECL_P (ref.ref))
{
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.
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.
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
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
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;
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);
&& 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;
}
&& 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);
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",
}
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 "
{
/* 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",
}
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",
{
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. */
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. */
static tree
compute_objsize (tree ptr, int ostype, access_ref *pref,
- const vr_values *rvals = NULL)
+ const vr_values *rvals /* = NULL */)
{
bitmap visited = NULL;
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.
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;
}
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;
}
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))
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;
}
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. */
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,
/* 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;
}
/* 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
/* 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
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. */
&& 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;
}
/* 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. */
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);
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. */
}
/* 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,
|| !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);
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)
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)
/* 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,
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. */
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;
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:
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;
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;
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;
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);
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):
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]);
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;
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;
{
/* 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. */
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)
{
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 ();
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
/* 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. */
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 */
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.
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);
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;
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;
}
}
}
}
+ 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
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]",
; /* 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
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 ? ", " : "";
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;
/* 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
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
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);
-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
@option{-Wstring-compare} is enabled by @option{-Wextra}.
+@item -Wno-stringop-overflow
@item -Wstringop-overflow
@itemx -Wstringop-overflow=@var{type}
@opindex Wstringop-overflow
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
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
{
/* 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;
}
/* 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;
}
{
/* 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;
}
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" }
}
{
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" }
}
-
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" } */
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));
}
/* 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"
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" } */
}
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" } */
}
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)
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)));
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)
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)
/* 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" } */
}
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)));
// 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" } { "" } }
// 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" } }
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" } */
}
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" } */
}
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__
{
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 };
{
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" }
}
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 *-*-* } }
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" }
}
/* 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;
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);
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. */
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);
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. */
/* 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" }
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" }
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);
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);
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);
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);
{
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)
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)
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" } */
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" } */
}
--- /dev/null
+/* 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" }
+}
--- /dev/null
+/* 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));
+}
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];
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\]+" } */
}
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 " } */
}
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);
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
{
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" } */
}
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\]+" } */
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\]+" } */
}
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\]+" } */
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\]+" } */
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\]+" } */
}
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\]+" } */
}
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" } */
}
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);
-/* 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__
/* 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
/* 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" } */
}
__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 } */
}
{
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" } */
}
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*);
{
/* 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);
}
/* 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" } { "" } } */
/* 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 ();
}
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)
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" } */
}
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" } */
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" } */
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" } */
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);
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);
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);
-/* 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;
f1 (S * s)
{
int result = 0;
- result += __builtin_memcmp (s->s, "a", 3);
+ result += __builtin_memcmp (s->s, "a", 3);
return result;
}
f2 (char *p)
{
int result = 0;
- result += __builtin_memcmp (p, "a", 3);
+ result += __builtin_memcmp (p, "a", 3);
return result;
}
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
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);
|| 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