Make full use of context-sensitive ranges in access warnings.

gcc/ChangeLog:

	* builtins.c (check_strncat_sizes): Pass access_data ctor additional
	arguments.
	(expand_builtin_memcmp): Move code to gimple-ssa-warn-access.cc.
	(expand_builtin_fork_or_exec): Same.
	* gimple-array-bounds.cc (array_bounds_checker::check_mem_ref): Pass
	compute_objsize additional arguments.
	(inbounds_memaccess_p): Same.
	(array_bounds_checker::check_array_bounds): Add an assert.  Stash
	statement in a member.
	(check_array_bounds_dom_walker::before_dom_children): Same.
	* gimple-array-bounds.h (array_bounds_checker::m_stmt): New member.
	* gimple-ssa-sprintf.c (get_destination_size): Add an argument.
	(handle_printf_call): Pass a new argument.
	* gimple-ssa-warn-access.cc (get_size_range): Add an argument.
	(check_access): Add an argument and pass it along to callees.
	(check_read_access): Make a member function.
	(pass_waccess::check_strcat): Pass access_data ctor additional
	arguments.
	(pass_waccess::check_strncat): Same.
	(pass_waccess::check_stxcpy): Same.
	(pass_waccess::check_stxncpy): Same.
	(pass_waccess::check_strncmp): Same.
	(pass_waccess::check_read_access): Same.
	(pass_waccess::check_builtin): Same.
	(pass_waccess::maybe_check_access_sizes): Same.
	(pass_waccess::maybe_check_dealloc_call): Same.
	* gimple-ssa-warn-access.h (check_read_access): Declare a new
	member function.
	* pointer-query.cc (compute_objsize_r): Add an argument.
	(gimple_call_return_array): Same.
	(gimple_call_alloc_size): Same.
	(access_ref::access_ref): Same.
	(access_ref::get_ref): Same.
	(pointer_query::get_ref): Same.
	(handle_min_max_size): Pass an arguments to callees.
	(handle_array_ref): Add an argument.
	(handle_mem_ref): Same.
	(compute_objsize): Same.
	* pointer-query.h (struct access_ref): Adjust signatures.
	(struct access_data): Same.
	(gimple_call_alloc_size): Add an argument.
	(gimple_parm_array_size): Same.
	(compute_objsize): Same.
	* tree-ssa-strlen.c (strlen_pass::adjust_last_stmt): Pass an additional
	argument to compute_objsize.
	(strlen_pass::maybe_warn_overflow): Same.
	(maybe_diag_stxncpy_trunc): Same.

gcc/testsuite/ChangeLog:

	* gcc.dg/Wstringop-overflow-22.c: Correct typos.
	* gcc.dg/Wstringop-overflow-81.c: New test.

libstdc++-v3/ChangeLog:

	* testsuite/21_strings/basic_string/capacity/1.cc: Also suppress
	-Wstringop-overread.
	* testsuite/27_io/filesystem/path/factory/u8path-char8_t.cc: Same.
This commit is contained in:
Martin Sebor 2021-10-26 14:38:11 -06:00
parent 88b504b7a8
commit 9a27acc30a
13 changed files with 267 additions and 230 deletions

View File

@ -3600,7 +3600,7 @@ check_strncat_sizes (tree exp, tree objsize)
/* Try to verify that the destination is big enough for the shortest
string. */
access_data data (exp, access_read_write, maxread, true);
access_data data (nullptr, exp, access_read_write, maxread, true);
if (!objsize && warn_stringop_overflow)
{
/* If it hasn't been provided by __strncat_chk, try to determine
@ -4260,12 +4260,6 @@ expand_builtin_memcmp (tree exp, rtx target, bool result_eq)
tree arg2 = CALL_EXPR_ARG (exp, 1);
tree len = CALL_EXPR_ARG (exp, 2);
/* Diagnose calls where the specified length exceeds the size of either
object. */
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;
@ -5486,27 +5480,6 @@ expand_builtin_fork_or_exec (tree fn, tree exp, rtx target, int ignore)
tree id, decl;
tree call;
if (DECL_FUNCTION_CODE (fn) != BUILT_IN_FORK)
{
tree path = CALL_EXPR_ARG (exp, 0);
/* Detect unterminated path. */
if (!check_read_access (exp, path))
return NULL_RTX;
/* Also detect unterminated first argument. */
switch (DECL_FUNCTION_CODE (fn))
{
case BUILT_IN_EXECL:
case BUILT_IN_EXECLE:
case BUILT_IN_EXECLP:
if (!check_read_access (exp, path))
return NULL_RTX;
default:
break;
}
}
/* If we are not profiling, just call the function. */
if (!profile_arc_flag)
return NULL_RTX;

View File

@ -426,7 +426,7 @@ array_bounds_checker::check_mem_ref (location_t location, tree ref,
axssize = wi::to_offset (access_size);
access_ref aref;
if (!compute_objsize (ref, 0, &aref, ranges))
if (!compute_objsize (ref, m_stmt, 0, &aref, ranges))
return false;
if (aref.offset_in_range (axssize))
@ -667,7 +667,7 @@ array_bounds_checker::check_addr_expr (location_t location, tree t,
problems discussed in pr98266 and pr97595. */
static bool
inbounds_memaccess_p (tree t)
inbounds_memaccess_p (tree t, gimple *stmt)
{
if (TREE_CODE (t) != COMPONENT_REF)
return false;
@ -686,7 +686,7 @@ inbounds_memaccess_p (tree t)
allocated). */
access_ref aref; // unused
tree refop = TREE_OPERAND (mref, 0);
tree refsize = compute_objsize (refop, 1, &aref);
tree refsize = compute_objsize (refop, stmt, 1, &aref);
if (!refsize || TREE_CODE (refsize) != INTEGER_CST)
return false;
@ -724,6 +724,7 @@ array_bounds_checker::check_array_bounds (tree *tp, int *walk_subtree,
{
tree t = *tp;
struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
location_t location;
if (EXPR_HAS_LOCATION (t))
@ -735,6 +736,8 @@ array_bounds_checker::check_array_bounds (tree *tp, int *walk_subtree,
bool warned = false;
array_bounds_checker *checker = (array_bounds_checker *) wi->info;
gcc_assert (checker->m_stmt == wi->stmt);
if (TREE_CODE (t) == ARRAY_REF)
warned = checker->check_array_ref (location, t, wi->stmt,
false/*ignore_off_by_one*/);
@ -746,7 +749,7 @@ array_bounds_checker::check_array_bounds (tree *tp, int *walk_subtree,
checker->check_addr_expr (location, t, wi->stmt);
*walk_subtree = false;
}
else if (inbounds_memaccess_p (t))
else if (inbounds_memaccess_p (t, wi->stmt))
/* Hack: Skip MEM_REF checks in accesses to a member of a base class
at an offset that's within the bounds of the enclosing object.
See pr98266 and pr97595. */
@ -794,14 +797,13 @@ check_array_bounds_dom_walker::before_dom_children (basic_block bb)
for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
{
gimple *stmt = gsi_stmt (si);
struct walk_stmt_info wi;
if (!gimple_has_location (stmt)
|| is_gimple_debug (stmt))
continue;
memset (&wi, 0, sizeof (wi));
struct walk_stmt_info wi{ };
wi.info = checker;
checker->m_stmt = stmt;
walk_gimple_op (stmt, array_bounds_checker::check_array_bounds, &wi);
}

View File

@ -36,8 +36,12 @@ private:
void check_addr_expr (location_t, tree, gimple *);
const value_range *get_value_range (const_tree op, gimple *);
/* Current function. */
struct function *fun;
/* Ranger instance. */
range_query *ranges;
/* Current statement. */
gimple *m_stmt;
};
#endif // GCC_GIMPLE_ARRAY_BOUNDS_H

View File

@ -4030,11 +4030,11 @@ compute_format_length (call_info &info, format_result *res, range_query *query)
return success;
}
/* Return the size of the object referenced by the expression DEST if
available, or the maximum possible size otherwise. */
/* Return the size of the object referenced by the expression DEST in
statement STMT, if available, or the maximum possible size otherwise. */
static unsigned HOST_WIDE_INT
get_destination_size (tree dest, pointer_query &ptr_qry)
get_destination_size (tree dest, gimple *stmt, pointer_query &ptr_qry)
{
/* When there is no destination return the maximum. */
if (!dest)
@ -4042,7 +4042,7 @@ get_destination_size (tree dest, pointer_query &ptr_qry)
/* Use compute_objsize to determine the size of the destination object. */
access_ref aref;
if (!ptr_qry.get_ref (dest, &aref))
if (!ptr_qry.get_ref (dest, stmt, &aref))
return HOST_WIDE_INT_MAX;
offset_int remsize = aref.size_remaining ();
@ -4516,7 +4516,7 @@ handle_printf_call (gimple_stmt_iterator *gsi, pointer_query &ptr_qry)
/* For non-bounded functions like sprintf, determine the size
of the destination from the object or pointer passed to it
as the first argument. */
dstsize = get_destination_size (dstptr, ptr_qry);
dstsize = get_destination_size (dstptr, info.callstmt, ptr_qry);
}
else if (tree size = gimple_call_arg (info.callstmt, idx_dstsize))
{

View File

@ -1190,11 +1190,11 @@ warn_for_access (location_t loc, tree func, tree expr, int opt,
by BNDRNG if nonnull and valid. */
static void
get_size_range (range_query *query, tree bound, tree range[2],
get_size_range (range_query *query, tree bound, gimple *stmt, tree range[2],
const offset_int bndrng[2])
{
if (bound)
get_size_range (query, bound, NULL, range);
get_size_range (query, bound, stmt, range);
if (!bndrng || (bndrng[0] == 0 && bndrng[1] == HOST_WIDE_INT_M1U))
return;
@ -1251,7 +1251,8 @@ template <class GimpleOrTree>
static bool
check_access (GimpleOrTree exp, tree dstwrite,
tree maxread, tree srcstr, tree dstsize,
access_mode mode, const access_data *pad /* = NULL */)
access_mode mode, const access_data *pad,
range_query *rvals)
{
/* The size of the largest object is half the address space, or
PTRDIFF_MAX. (This is way too permissive.) */
@ -1338,7 +1339,8 @@ check_access (GimpleOrTree exp, tree dstwrite,
/* Set RANGE to that of DSTWRITE if non-null, bounded by PAD->DST.BNDRNG
if valid. */
get_size_range (NULL, dstwrite, range, pad ? pad->dst.bndrng : NULL);
gimple *stmt = pad ? pad->stmt : nullptr;
get_size_range (rvals, dstwrite, stmt, range, pad ? pad->dst.bndrng : NULL);
tree func = get_callee_fndecl (exp);
/* Read vs write access by built-ins can be determined from the const
@ -1432,7 +1434,7 @@ check_access (GimpleOrTree exp, tree dstwrite,
{
/* Set RANGE to that of MAXREAD, bounded by PAD->SRC.BNDRNG if
PAD is nonnull and BNDRNG is valid. */
get_size_range (NULL, maxread, range, pad ? pad->src.bndrng : NULL);
get_size_range (rvals, maxread, stmt, range, pad ? pad->src.bndrng : NULL);
location_t loc = get_location (exp);
tree size = dstsize;
@ -1479,7 +1481,7 @@ check_access (GimpleOrTree exp, tree dstwrite,
{
/* Set RANGE to that of MAXREAD, bounded by PAD->SRC.BNDRNG if
PAD is nonnull and BNDRNG is valid. */
get_size_range (NULL, maxread, range, pad ? pad->src.bndrng : NULL);
get_size_range (rvals, maxread, stmt, 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]);
@ -1512,13 +1514,14 @@ check_access (GimpleOrTree exp, tree dstwrite,
return true;
}
bool
static bool
check_access (gimple *stmt, tree dstwrite,
tree maxread, tree srcstr, tree dstsize,
access_mode mode, const access_data *pad /* = NULL */)
access_mode mode, const access_data *pad,
range_query *rvals)
{
return check_access<gimple *>(stmt, dstwrite, maxread, srcstr, dstsize,
mode, pad);
return check_access<gimple *> (stmt, dstwrite, maxread, srcstr, dstsize,
mode, pad, rvals);
}
bool
@ -1526,45 +1529,8 @@ check_access (tree expr, tree dstwrite,
tree maxread, tree srcstr, tree dstsize,
access_mode mode, const access_data *pad /* = NULL */)
{
return check_access<tree>(expr, dstwrite, maxread, srcstr, dstsize,
mode, pad);
}
/* A convenience wrapper for check_access above to check access
by a read-only function like puts. */
template <class GimpleOrTree>
static bool
check_read_access (GimpleOrTree expr, tree src, tree bound, int ost)
{
if (!warn_stringop_overread)
return true;
if (bound && !useless_type_conversion_p (size_type_node, TREE_TYPE (bound)))
bound = fold_convert (size_type_node, bound);
tree fndecl = get_callee_fndecl (expr);
maybe_warn_nonstring_arg (fndecl, expr);
access_data data (expr, access_read_only, NULL_TREE, false, bound, true);
compute_objsize (src, ost, &data.src);
return check_access (expr, /*dstwrite=*/ NULL_TREE, /*maxread=*/ bound,
/*srcstr=*/ src, /*dstsize=*/ NULL_TREE, data.mode,
&data);
}
bool
check_read_access (gimple *stmt, tree src, tree bound /* = NULL_TREE */,
int ost /* = 1 */)
{
return check_read_access<gimple *>(stmt, src, bound, ost);
}
bool
check_read_access (tree expr, tree src, tree bound /* = NULL_TREE */,
int ost /* = 1 */)
{
return check_read_access<tree>(expr, src, bound, ost);
return check_access<tree> (expr, dstwrite, maxread, srcstr, dstsize,
mode, pad, nullptr);
}
/* Return true if STMT is a call to an allocation function. Unless
@ -2133,6 +2099,7 @@ private:
void check_stxncpy (gcall *);
void check_strncmp (gcall *);
void check_memop_access (gimple *, tree, tree, tree);
void check_read_access (gimple *, tree, tree = NULL_TREE, int = 1);
void maybe_check_dealloc_call (gcall *);
void maybe_check_access_sizes (rdwr_map *, tree, tree, gimple *);
@ -2428,14 +2395,14 @@ pass_waccess::check_strcat (gcall *stmt)
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 (stmt, access_read_write, NULL_TREE, true,
NULL_TREE, true);
access_data data (m_ptr_qry.rvals, stmt, 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, &m_ptr_qry);
tree destsize = compute_objsize (dest, ost, &data.dst, &m_ptr_qry);
compute_objsize (src, stmt, ost, &data.src, &m_ptr_qry);
tree destsize = compute_objsize (dest, stmt, ost, &data.dst, &m_ptr_qry);
check_access (stmt, /*dstwrite=*/NULL_TREE, /*maxread=*/NULL_TREE,
src, destsize, data.mode, &data);
src, destsize, data.mode, &data, m_ptr_qry.rvals);
}
/* Check a call STMT to strcat() for overflow and warn if it does. */
@ -2469,12 +2436,12 @@ pass_waccess::check_strncat (gcall *stmt)
maxlen = lendata.maxbound;
}
access_data data (stmt, access_read_write);
access_data data (m_ptr_qry.rvals, stmt, 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. */
const int ost = warn_stringop_overflow - 1;
tree destsize = compute_objsize (dest, ost, &data.dst, &m_ptr_qry);
tree destsize = compute_objsize (dest, stmt, ost, &data.dst, &m_ptr_qry);
/* Add one for the terminating nul. */
tree srclen = (maxlen
@ -2503,7 +2470,7 @@ pass_waccess::check_strncat (gcall *stmt)
srclen = maxread;
check_access (stmt, /*dstwrite=*/NULL_TREE, maxread, srclen,
destsize, data.mode, &data);
destsize, data.mode, &data, m_ptr_qry.rvals);
}
/* Check a call STMT to stpcpy() or strcpy() for overflow and warn
@ -2527,14 +2494,14 @@ pass_waccess::check_stxcpy (gcall *stmt)
if (warn_stringop_overflow)
{
access_data data (stmt, access_read_write, NULL_TREE, true,
NULL_TREE, true);
access_data data (m_ptr_qry.rvals, stmt, 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, &m_ptr_qry);
tree dstsize = compute_objsize (dst, ost, &data.dst, &m_ptr_qry);
compute_objsize (src, stmt, ost, &data.src, &m_ptr_qry);
tree dstsize = compute_objsize (dst, stmt, ost, &data.dst, &m_ptr_qry);
check_access (stmt, /*dstwrite=*/ NULL_TREE,
/*maxread=*/ NULL_TREE, /*srcstr=*/ src,
dstsize, data.mode, &data);
dstsize, data.mode, &data, m_ptr_qry.rvals);
}
/* Check to see if the argument was declared attribute nonstring
@ -2558,13 +2525,14 @@ pass_waccess::check_stxncpy (gcall *stmt)
/* The number of bytes to write (not the maximum). */
tree len = call_arg (stmt, 2);
access_data data (stmt, access_read_write, len, true, len, true);
access_data data (m_ptr_qry.rvals, stmt, access_read_write, len, true, len,
true);
const int ost = warn_stringop_overflow ? warn_stringop_overflow - 1 : 1;
compute_objsize (src, ost, &data.src, &m_ptr_qry);
tree dstsize = compute_objsize (dst, ost, &data.dst, &m_ptr_qry);
compute_objsize (src, stmt, ost, &data.src, &m_ptr_qry);
tree dstsize = compute_objsize (dst, stmt, ost, &data.dst, &m_ptr_qry);
check_access (stmt, /*dstwrite=*/len,
/*maxread=*/len, src, dstsize, data.mode, &data);
check_access (stmt, /*dstwrite=*/len, /*maxread=*/len, src, dstsize,
data.mode, &data, m_ptr_qry.rvals);
}
/* Check a call STMT to stpncpy() or strncpy() for overflow and warn
@ -2597,6 +2565,11 @@ pass_waccess::check_strncmp (gcall *stmt)
tree len1 = c_strlen (arg1, 1, &lendata1);
tree len2 = c_strlen (arg2, 1, &lendata2);
if (len1 && TREE_CODE (len1) != INTEGER_CST)
len1 = NULL_TREE;
if (len2 && TREE_CODE (len2) != INTEGER_CST)
len2 = NULL_TREE;
if (len1 && len2)
/* If the length of both arguments was computed they must both be
nul-terminated and no further checking is necessary regardless
@ -2609,13 +2582,15 @@ pass_waccess::check_strncmp (gcall *stmt)
if (maybe_warn_nonstring_arg (get_callee_fndecl (stmt), stmt))
return;
access_data adata1 (stmt, access_read_only, NULL_TREE, false, bound, true);
access_data adata2 (stmt, access_read_only, NULL_TREE, false, bound, true);
access_data adata1 (m_ptr_qry.rvals, stmt, access_read_only, NULL_TREE, false,
bound, true);
access_data adata2 (m_ptr_qry.rvals, stmt, access_read_only, NULL_TREE, false,
bound, true);
/* Determine the range of the bound first and bail if it fails; it's
cheaper than computing the size of the objects. */
tree bndrng[2] = { NULL_TREE, NULL_TREE };
get_size_range (m_ptr_qry.rvals, bound, bndrng, adata1.src.bndrng);
get_size_range (m_ptr_qry.rvals, bound, stmt, bndrng, adata1.src.bndrng);
if (!bndrng[0] || integer_zerop (bndrng[0]))
return;
@ -2626,8 +2601,8 @@ pass_waccess::check_strncmp (gcall *stmt)
/* compute_objsize almost never fails (and ultimately should never
fail). Don't bother to handle the rare case when it does. */
if (!compute_objsize (arg1, 1, &adata1.src, &m_ptr_qry)
|| !compute_objsize (arg2, 1, &adata2.src, &m_ptr_qry))
if (!compute_objsize (arg1, stmt, 1, &adata1.src, &m_ptr_qry)
|| !compute_objsize (arg2, stmt, 1, &adata2.src, &m_ptr_qry))
return;
/* Compute the size of the remaining space in each array after
@ -2675,15 +2650,41 @@ pass_waccess::check_memop_access (gimple *stmt, tree dest, tree src, tree size)
try to determine the size of the largest source and destination
object using type-0 Object Size regardless of the object size
type specified by the option. */
access_data data (stmt, access_read_write);
access_data data (m_ptr_qry.rvals, stmt, access_read_write);
tree srcsize
= src ? compute_objsize (src, 0, &data.src, &m_ptr_qry) : NULL_TREE;
tree dstsize = compute_objsize (dest, 0, &data.dst, &m_ptr_qry);
= src ? compute_objsize (src, stmt, 0, &data.src, &m_ptr_qry) : NULL_TREE;
tree dstsize = compute_objsize (dest, stmt, 0, &data.dst, &m_ptr_qry);
check_access (stmt, size, /*maxread=*/NULL_TREE,
srcsize, dstsize, data.mode, &data);
check_access (stmt, size, /*maxread=*/NULL_TREE, srcsize, dstsize,
data.mode, &data, m_ptr_qry.rvals);
}
/* A convenience wrapper for check_access to check access by a read-only
function like puts or strcmp. */
void
pass_waccess::check_read_access (gimple *stmt, tree src,
tree bound /* = NULL_TREE */,
int ost /* = 1 */)
{
if (!warn_stringop_overread)
return;
if (bound && !useless_type_conversion_p (size_type_node, TREE_TYPE (bound)))
bound = fold_convert (size_type_node, bound);
tree fndecl = get_callee_fndecl (stmt);
maybe_warn_nonstring_arg (fndecl, stmt);
access_data data (m_ptr_qry.rvals, stmt, access_read_only, NULL_TREE,
false, bound, true);
compute_objsize (src, stmt, ost, &data.src, &m_ptr_qry);
check_access (stmt, /*dstwrite=*/ NULL_TREE, /*maxread=*/ bound,
/*srcstr=*/ src, /*dstsize=*/ NULL_TREE, data.mode,
&data, m_ptr_qry.rvals);
}
/* Check a call STMT to an atomic or sync built-in. */
bool
@ -2783,6 +2784,15 @@ pass_waccess::check_builtin (gcall *stmt)
check_alloca (stmt);
return true;
case BUILT_IN_EXECL:
case BUILT_IN_EXECLE:
case BUILT_IN_EXECLP:
case BUILT_IN_EXECV:
case BUILT_IN_EXECVE:
case BUILT_IN_EXECVP:
check_read_access (stmt, call_arg (stmt, 0));
return true;
case BUILT_IN_GETTEXT:
case BUILT_IN_PUTS:
case BUILT_IN_PUTS_UNLOCKED:
@ -2805,8 +2815,12 @@ pass_waccess::check_builtin (gcall *stmt)
case BUILT_IN_STRNDUP:
case BUILT_IN_STRNLEN:
check_read_access (stmt, call_arg (stmt, 0), call_arg (stmt, 1));
return true;
{
tree str = call_arg (stmt, 0);
tree len = call_arg (stmt, 1);
check_read_access (stmt, str, len);
return true;
}
case BUILT_IN_STRCAT:
check_strcat (stmt);
@ -2985,7 +2999,7 @@ pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, tree fndecl, tree fntype,
/* Format the value or range to avoid an explosion of messages. */
char sizstr[80];
tree sizrng[2] = { size_zero_node, build_all_ones_cst (sizetype) };
if (get_size_range (m_ptr_qry.rvals, access_size, NULL, sizrng, 1))
if (get_size_range (m_ptr_qry.rvals, access_size, stmt, sizrng, 1))
{
char *s0 = print_generic_expr_to_str (sizrng[0]);
if (tree_int_cst_equal (sizrng[0], sizrng[1]))
@ -3113,11 +3127,11 @@ pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, tree fndecl, tree fntype,
}
}
access_data data (ptr, access.second.mode, NULL_TREE, false,
NULL_TREE, false);
access_data data (m_ptr_qry.rvals, stmt, access.second.mode,
NULL_TREE, false, NULL_TREE, false);
access_ref* const pobj = (access.second.mode == access_write_only
? &data.dst : &data.src);
tree objsize = compute_objsize (ptr, 1, pobj, &m_ptr_qry);
tree objsize = compute_objsize (ptr, stmt, 1, pobj, &m_ptr_qry);
/* The size of the destination or source object. */
tree dstsize = NULL_TREE, srcsize = NULL_TREE;
@ -3149,7 +3163,7 @@ pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, tree fndecl, tree fntype,
if (mode == access_deferred)
mode = TYPE_READONLY (argtype) ? access_read_only : access_read_write;
check_access (stmt, access_size, /*maxread=*/ NULL_TREE, srcsize,
dstsize, mode, &data);
dstsize, mode, &data, m_ptr_qry.rvals);
if (warning_suppressed_p (stmt, OPT_Wstringop_overflow_))
opt_warned = OPT_Wstringop_overflow_;
@ -3272,7 +3286,7 @@ pass_waccess::maybe_check_dealloc_call (gcall *call)
return;
access_ref aref;
if (!compute_objsize (ptr, 0, &aref, &m_ptr_qry))
if (!compute_objsize (ptr, call, 0, &aref, &m_ptr_qry))
return;
tree ref = aref.ref;

View File

@ -45,7 +45,4 @@ class access_data;
extern bool check_access (tree, tree, tree, tree, tree, access_mode,
const access_data * = NULL);
extern bool check_read_access (gimple *, tree, tree = NULL_TREE, int ost = 1);
extern bool check_read_access (tree, tree, tree = NULL_TREE, int = 1);
#endif // GCC_GIMPLE_SSA_WARN_ACCESS_H

View File

@ -43,8 +43,8 @@
#include "tree-ssanames.h"
#include "target.h"
static bool compute_objsize_r (tree, int, access_ref *, ssa_name_limit_t &,
pointer_query *);
static bool compute_objsize_r (tree, gimple *, int, access_ref *,
ssa_name_limit_t &, pointer_query *);
/* Wrapper around the wide_int overload of get_range that accepts
offset_int instead. For middle end expressions returns the same
@ -115,7 +115,7 @@ get_offset_range (tree x, gimple *stmt, offset_int r[2], range_query *rvals)
static tree
gimple_call_return_array (gimple *stmt, offset_int offrng[2], bool *past_end,
range_query *rvals)
ssa_name_limit_t &snlim, pointer_query *qry)
{
/* Clear and set below for the rare function(s) that might return
a past-the-end pointer. */
@ -191,7 +191,7 @@ gimple_call_return_array (gimple *stmt, offset_int offrng[2], bool *past_end,
offrng[0] = 0;
offrng[1] = HOST_WIDE_INT_M1U;
tree off = gimple_call_arg (stmt, 2);
bool off_valid = get_offset_range (off, stmt, offrng, rvals);
bool off_valid = get_offset_range (off, stmt, offrng, qry->rvals);
if (!off_valid || offrng[0] != offrng[1])
{
/* If the offset is either indeterminate or in some range,
@ -199,7 +199,7 @@ gimple_call_return_array (gimple *stmt, offset_int offrng[2], bool *past_end,
of the source object. */
access_ref aref;
tree src = gimple_call_arg (stmt, 1);
if (compute_objsize (src, 1, &aref, rvals)
if (compute_objsize (src, stmt, 1, &aref, qry)
&& aref.sizrng[1] < offrng[1])
offrng[1] = aref.sizrng[1];
}
@ -212,7 +212,7 @@ gimple_call_return_array (gimple *stmt, offset_int offrng[2], bool *past_end,
case BUILT_IN_MEMCHR:
{
tree off = gimple_call_arg (stmt, 2);
if (get_offset_range (off, stmt, offrng, rvals))
if (get_offset_range (off, stmt, offrng, qry->rvals))
offrng[1] -= 1;
else
offrng[1] = HOST_WIDE_INT_M1U;
@ -233,7 +233,7 @@ gimple_call_return_array (gimple *stmt, offset_int offrng[2], bool *past_end,
{
access_ref aref;
tree src = gimple_call_arg (stmt, 1);
if (compute_objsize (src, 1, &aref, rvals))
if (compute_objsize_r (src, stmt, 1, &aref, snlim, qry))
offrng[1] = aref.sizrng[1] - 1;
else
offrng[1] = HOST_WIDE_INT_M1U;
@ -250,7 +250,7 @@ gimple_call_return_array (gimple *stmt, offset_int offrng[2], bool *past_end,
and the source object size. */
offrng[1] = HOST_WIDE_INT_M1U;
tree off = gimple_call_arg (stmt, 2);
if (!get_offset_range (off, stmt, offrng, rvals)
if (!get_offset_range (off, stmt, offrng, qry->rvals)
|| offrng[0] != offrng[1])
{
/* If the offset is either indeterminate or in some range,
@ -258,7 +258,7 @@ gimple_call_return_array (gimple *stmt, offset_int offrng[2], bool *past_end,
of the source object. */
access_ref aref;
tree src = gimple_call_arg (stmt, 1);
if (compute_objsize (src, 1, &aref, rvals)
if (compute_objsize_r (src, stmt, 1, &aref, snlim, qry)
&& aref.sizrng[1] < offrng[1])
offrng[1] = aref.sizrng[1];
}
@ -445,7 +445,7 @@ get_size_range (tree exp, tree range[2], int flags /* = 0 */)
tree
gimple_call_alloc_size (gimple *stmt, wide_int rng1[2] /* = NULL */,
range_query * /* = NULL */)
range_query *qry /* = NULL */)
{
if (!stmt || !is_gimple_call (stmt))
return NULL_TREE;
@ -503,7 +503,7 @@ gimple_call_alloc_size (gimple *stmt, wide_int rng1[2] /* = NULL */,
{
tree r[2];
/* Determine the largest valid range size, including zero. */
if (!get_size_range (size, r, SR_ALLOW_ZERO | SR_USE_LARGEST))
if (!get_size_range (qry, size, stmt, r, SR_ALLOW_ZERO | SR_USE_LARGEST))
return NULL_TREE;
rng1[0] = wi::to_wide (r[0], prec);
rng1[1] = wi::to_wide (r[1], prec);
@ -519,7 +519,7 @@ gimple_call_alloc_size (gimple *stmt, wide_int rng1[2] /* = NULL */,
{
tree r[2];
/* As above, use the full non-negative range on failure. */
if (!get_size_range (n, r, SR_ALLOW_ZERO | SR_USE_LARGEST))
if (!get_size_range (qry, n, stmt, r, SR_ALLOW_ZERO | SR_USE_LARGEST))
return NULL_TREE;
rng2[0] = wi::to_wide (r[0], prec);
rng2[1] = wi::to_wide (r[1], prec);
@ -546,7 +546,7 @@ gimple_call_alloc_size (gimple *stmt, wide_int rng1[2] /* = NULL */,
Set STATIC_ARRAY if the array parameter has been declared [static].
Return the function parameter on success and null otherwise. */
tree
static tree
gimple_parm_array_size (tree ptr, wide_int rng[2],
bool *static_array /* = NULL */)
{
@ -596,10 +596,17 @@ gimple_parm_array_size (tree ptr, wide_int rng[2],
return var;
}
access_ref::access_ref (tree bound /* = NULL_TREE */,
/* Given a statement STMT, set the bounds of the reference to at most
as many bytes as BOUND or unknown when null, and at least one when
the MINACCESS is true unless BOUND is a constant zero. STMT is
used for context to get accurate range info. */
access_ref::access_ref (range_query *qry /* = nullptr */,
tree bound /* = NULL_TREE */,
gimple *stmt /* = nullptr */,
bool minaccess /* = false */)
: ref (), eval ([](tree x){ return x; }), deref (), trail1special (true),
base0 (true), parmarray ()
: ref (), eval ([](tree x){ return x; }), deref (), trail1special (true),
base0 (true), parmarray ()
{
/* Set to valid. */
offrng[0] = offrng[1] = 0;
@ -615,7 +622,7 @@ access_ref::access_ref (tree bound /* = NULL_TREE */,
set the bounds of the access to reflect both it and MINACCESS.
BNDRNG[0] is the size of the minimum access. */
tree rng[2];
if (bound && get_size_range (bound, rng, SR_ALLOW_ZERO))
if (bound && get_size_range (qry, bound, stmt, rng, SR_ALLOW_ZERO))
{
bndrng[0] = wi::to_offset (rng[0]);
bndrng[1] = wi::to_offset (rng[1]);
@ -696,7 +703,8 @@ access_ref::get_ref (vec<access_ref> *all_refs,
{
access_ref phi_arg_ref;
tree arg = gimple_phi_arg_def (phi_stmt, i);
if (!compute_objsize_r (arg, ostype, &phi_arg_ref, *psnlim, qry)
if (!compute_objsize_r (arg, phi_stmt, ostype, &phi_arg_ref, *psnlim,
qry)
|| phi_arg_ref.sizrng[0] < 0)
/* A PHI with all null pointer arguments. */
return NULL_TREE;
@ -1312,7 +1320,7 @@ pointer_query::get_ref (tree ptr, int ostype /* = 1 */) const
there or compute it and insert it into the cache if it's nonnonull. */
bool
pointer_query::get_ref (tree ptr, access_ref *pref, int ostype /* = 1 */)
pointer_query::get_ref (tree ptr, gimple *stmt, access_ref *pref, int ostype /* = 1 */)
{
const unsigned version
= TREE_CODE (ptr) == SSA_NAME ? SSA_NAME_VERSION (ptr) : 0;
@ -1335,7 +1343,7 @@ pointer_query::get_ref (tree ptr, access_ref *pref, int ostype /* = 1 */)
++misses;
}
if (!compute_objsize (ptr, ostype, pref, this))
if (!compute_objsize (ptr, stmt, ostype, pref, this))
{
++failures;
return false;
@ -1502,7 +1510,7 @@ static bool
handle_min_max_size (tree ptr, int ostype, access_ref *pref,
ssa_name_limit_t &snlim, pointer_query *qry)
{
const gimple *stmt = SSA_NAME_DEF_STMT (ptr);
gimple *stmt = SSA_NAME_DEF_STMT (ptr);
const tree_code code = gimple_assign_rhs_code (stmt);
/* In a valid MAX_/MIN_EXPR both operands must refer to the same array.
@ -1512,7 +1520,7 @@ handle_min_max_size (tree ptr, int ostype, access_ref *pref,
for the expression. */
access_ref aref[2] = { *pref, *pref };
tree arg1 = gimple_assign_rhs1 (stmt);
if (!compute_objsize_r (arg1, ostype, &aref[0], snlim, qry))
if (!compute_objsize_r (arg1, stmt, ostype, &aref[0], snlim, qry))
{
aref[0].base0 = false;
aref[0].offrng[0] = aref[0].offrng[1] = 0;
@ -1521,7 +1529,7 @@ handle_min_max_size (tree ptr, int ostype, access_ref *pref,
}
tree arg2 = gimple_assign_rhs2 (stmt);
if (!compute_objsize_r (arg2, ostype, &aref[1], snlim, qry))
if (!compute_objsize_r (arg2, stmt, ostype, &aref[1], snlim, qry))
{
aref[1].base0 = false;
aref[1].offrng[0] = aref[1].offrng[1] = 0;
@ -1589,8 +1597,9 @@ handle_min_max_size (tree ptr, int ostype, access_ref *pref,
on success and false on failure. */
static bool
handle_array_ref (tree aref, bool addr, int ostype, access_ref *pref,
ssa_name_limit_t &snlim, pointer_query *qry)
handle_array_ref (tree aref, gimple *stmt, bool addr, int ostype,
access_ref *pref, ssa_name_limit_t &snlim,
pointer_query *qry)
{
gcc_assert (TREE_CODE (aref) == ARRAY_REF);
@ -1603,7 +1612,7 @@ handle_array_ref (tree aref, bool addr, int ostype, access_ref *pref,
of known bound. */
return false;
if (!compute_objsize_r (arefop, ostype, pref, snlim, qry))
if (!compute_objsize_r (arefop, stmt, ostype, pref, snlim, qry))
return false;
offset_int orng[2];
@ -1668,7 +1677,7 @@ handle_array_ref (tree aref, bool addr, int ostype, access_ref *pref,
MREF. Return true on success and false on failure. */
static bool
handle_mem_ref (tree mref, int ostype, access_ref *pref,
handle_mem_ref (tree mref, gimple *stmt, int ostype, access_ref *pref,
ssa_name_limit_t &snlim, pointer_query *qry)
{
gcc_assert (TREE_CODE (mref) == MEM_REF);
@ -1690,7 +1699,7 @@ handle_mem_ref (tree mref, int ostype, access_ref *pref,
}
tree mrefop = TREE_OPERAND (mref, 0);
if (!compute_objsize_r (mrefop, ostype, pref, snlim, qry))
if (!compute_objsize_r (mrefop, stmt, ostype, pref, snlim, qry))
return false;
offset_int orng[2];
@ -1723,7 +1732,7 @@ handle_mem_ref (tree mref, int ostype, access_ref *pref,
to influence code generation or optimization. */
static bool
compute_objsize_r (tree ptr, int ostype, access_ref *pref,
compute_objsize_r (tree ptr, gimple *stmt, int ostype, access_ref *pref,
ssa_name_limit_t &snlim, pointer_query *qry)
{
STRIP_NOPS (ptr);
@ -1774,7 +1783,7 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref,
if (code == BIT_FIELD_REF)
{
tree ref = TREE_OPERAND (ptr, 0);
if (!compute_objsize_r (ref, ostype, pref, snlim, qry))
if (!compute_objsize_r (ref, stmt, ostype, pref, snlim, qry))
return false;
offset_int off = wi::to_offset (pref->eval (TREE_OPERAND (ptr, 2)));
@ -1796,7 +1805,7 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref,
/* In OSTYPE zero (for raw memory functions like memcpy), use
the maximum size instead if the identity of the enclosing
object cannot be determined. */
if (!compute_objsize_r (ref, ostype, pref, snlim, qry))
if (!compute_objsize_r (ref, stmt, ostype, pref, snlim, qry))
return false;
/* Otherwise, use the size of the enclosing object and add
@ -1850,15 +1859,15 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref,
}
if (code == ARRAY_REF)
return handle_array_ref (ptr, addr, ostype, pref, snlim, qry);
return handle_array_ref (ptr, stmt, addr, ostype, pref, snlim, qry);
if (code == MEM_REF)
return handle_mem_ref (ptr, ostype, pref, snlim, qry);
return handle_mem_ref (ptr, stmt, ostype, pref, snlim, qry);
if (code == TARGET_MEM_REF)
{
tree ref = TREE_OPERAND (ptr, 0);
if (!compute_objsize_r (ref, ostype, pref, snlim, qry))
if (!compute_objsize_r (ref, stmt, ostype, pref, snlim, qry))
return false;
/* TODO: Handle remaining operands. Until then, add maximum offset. */
@ -1903,7 +1912,7 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref,
if (code == POINTER_PLUS_EXPR)
{
tree ref = TREE_OPERAND (ptr, 0);
if (!compute_objsize_r (ref, ostype, pref, snlim, qry))
if (!compute_objsize_r (ref, stmt, ostype, pref, snlim, qry))
return false;
/* Clear DEREF since the offset is being applied to the target
@ -1922,7 +1931,7 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref,
if (code == VIEW_CONVERT_EXPR)
{
ptr = TREE_OPERAND (ptr, 0);
return compute_objsize_r (ptr, ostype, pref, snlim, qry);
return compute_objsize_r (ptr, stmt, ostype, pref, snlim, qry);
}
if (code == SSA_NAME)
@ -1951,7 +1960,7 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref,
}
}
gimple *stmt = SSA_NAME_DEF_STMT (ptr);
stmt = SSA_NAME_DEF_STMT (ptr);
if (is_gimple_call (stmt))
{
/* If STMT is a call to an allocation function get the size
@ -1979,9 +1988,9 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref,
bool past_end;
offset_int offrng[2];
if (tree ret = gimple_call_return_array (stmt, offrng,
&past_end, rvals))
&past_end, snlim, qry))
{
if (!compute_objsize_r (ret, ostype, pref, snlim, qry))
if (!compute_objsize_r (ret, stmt, ostype, pref, snlim, qry))
return false;
/* Cap OFFRNG[1] to at most the remaining size of
@ -2076,14 +2085,14 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref,
if (code == ASSERT_EXPR)
{
rhs = TREE_OPERAND (rhs, 0);
return compute_objsize_r (rhs, ostype, pref, snlim, qry);
return compute_objsize_r (rhs, stmt, ostype, pref, snlim, qry);
}
if (code == POINTER_PLUS_EXPR
&& TREE_CODE (TREE_TYPE (rhs)) == POINTER_TYPE)
{
/* Compute the size of the object first. */
if (!compute_objsize_r (rhs, ostype, pref, snlim, qry))
if (!compute_objsize_r (rhs, stmt, ostype, pref, snlim, qry))
return false;
offset_int orng[2];
@ -2099,7 +2108,7 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref,
if (code == ADDR_EXPR || code == SSA_NAME)
{
if (!compute_objsize_r (rhs, ostype, pref, snlim, qry))
if (!compute_objsize_r (rhs, stmt, ostype, pref, snlim, qry))
return false;
qry->put_ref (ptr, *pref);
return true;
@ -2128,31 +2137,8 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref,
instead. */
tree
compute_objsize (tree ptr, int ostype, access_ref *pref,
range_query *rvals /* = NULL */)
{
pointer_query qry;
qry.rvals = rvals;
/* Clear and invalidate in case *PREF is being reused. */
pref->offrng[0] = pref->offrng[1] = 0;
pref->sizrng[0] = pref->sizrng[1] = -1;
ssa_name_limit_t snlim;
if (!compute_objsize_r (ptr, ostype, pref, snlim, &qry))
return NULL_TREE;
offset_int maxsize = pref->size_remaining ();
if (pref->base0 && pref->offrng[0] < 0 && pref->offrng[1] >= 0)
pref->offrng[0] = 0;
return wide_int_to_tree (sizetype, maxsize);
}
/* Transitional wrapper. The function should be removed once callers
transition to the pointer_query API. */
tree
compute_objsize (tree ptr, int ostype, access_ref *pref, pointer_query *ptr_qry)
compute_objsize (tree ptr, gimple *stmt, int ostype, access_ref *pref,
pointer_query *ptr_qry)
{
pointer_query qry;
if (ptr_qry)
@ -2165,7 +2151,7 @@ compute_objsize (tree ptr, int ostype, access_ref *pref, pointer_query *ptr_qry)
pref->sizrng[0] = pref->sizrng[1] = -1;
ssa_name_limit_t snlim;
if (!compute_objsize_r (ptr, ostype, pref, snlim, ptr_qry))
if (!compute_objsize_r (ptr, stmt, ostype, pref, snlim, ptr_qry))
return NULL_TREE;
offset_int maxsize = pref->size_remaining ();
@ -2174,6 +2160,18 @@ compute_objsize (tree ptr, int ostype, access_ref *pref, pointer_query *ptr_qry)
return wide_int_to_tree (sizetype, maxsize);
}
/* Transitional wrapper. The function should be removed once callers
transition to the pointer_query API. */
tree
compute_objsize (tree ptr, gimple *stmt, int ostype, access_ref *pref,
range_query *rvals /* = NULL */)
{
pointer_query qry;
qry.rvals = rvals;
return compute_objsize (ptr, stmt, ostype, pref, &qry);
}
/* Legacy wrapper around the above. The function should be removed
once callers transition to one of the two above. */
@ -2184,7 +2182,7 @@ compute_objsize (tree ptr, int ostype, tree *pdecl /* = NULL */,
/* Set the initial offsets to zero and size to negative to indicate
none has been computed yet. */
access_ref ref;
tree size = compute_objsize (ptr, ostype, &ref, rvals);
tree size = compute_objsize (ptr, nullptr, ostype, &ref, rvals);
if (!size || !ref.base0)
return NULL_TREE;

View File

@ -60,18 +60,16 @@ class pointer_query;
/* Describes a reference to an object used in an access. */
struct access_ref
{
/* 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);
/* Set the bounds of the reference. */
access_ref (range_query *query = nullptr, tree = NULL_TREE,
gimple * = nullptr, bool = false);
/* Return the PHI node REF refers to or null if it doesn't. */
gphi *phi () const;
/* Return the object to which REF refers. */
tree get_ref (vec<access_ref> *, access_ref * = NULL, int = 1,
ssa_name_limit_t * = NULL, pointer_query * = NULL) const;
tree get_ref (vec<access_ref> *, access_ref * = nullptr, int = 1,
ssa_name_limit_t * = nullptr, pointer_query * = nullptr) const;
/* Return true if OFFRNG is the constant zero. */
bool offset_zero () const
@ -85,7 +83,7 @@ struct access_ref
/* Return the maximum amount of space remaining and if non-null, set
argument to the minimum. */
offset_int size_remaining (offset_int * = NULL) const;
offset_int size_remaining (offset_int * = nullptr) const;
/* Return true if the offset and object size are in range for SIZE. */
bool offset_in_range (const offset_int &) const;
@ -172,13 +170,13 @@ public:
};
/* Construct an object with the given Ranger instance and cache. */
explicit pointer_query (range_query * = NULL, cache_type * = NULL);
explicit pointer_query (range_query * = nullptr, cache_type * = nullptr);
/* Retrieve the access_ref for a variable from cache if it's there. */
const access_ref* get_ref (tree, int = 1) const;
/* Retrieve the access_ref for a variable from cache or compute it. */
bool get_ref (tree, access_ref*, int = 1);
bool get_ref (tree, gimple *, access_ref*, int = 1);
/* Add an access_ref for the SSA_NAME to the cache. */
void put_ref (tree, const access_ref&, int = 1);
@ -208,19 +206,23 @@ 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 (gimple *stmt, access_mode mode,
access_data (range_query *query, gimple *stmt, access_mode mode,
tree maxwrite = NULL_TREE, bool minwrite = false,
tree maxread = NULL_TREE, bool minread = false)
: stmt (stmt), call (),
dst (maxwrite, minwrite), src (maxread, minread), mode (mode) { }
dst (query, maxwrite, stmt, minwrite),
src (query, maxread, stmt, minread),
mode (mode) { }
/* 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,
access_data (range_query *query, tree expr, access_mode mode,
tree maxwrite = NULL_TREE, bool minwrite = false,
tree maxread = NULL_TREE, bool minread = false)
: stmt (), call (expr),
dst (maxwrite, minwrite), src (maxread, minread), mode (mode) { }
dst (query, maxwrite, nullptr, minwrite),
src (query, maxread, nullptr, minread),
mode (mode) { }
/* Access statement. */
gimple *stmt;
@ -245,14 +247,23 @@ extern bool get_size_range (tree, tree[2], int = 0);
extern bool get_size_range (range_query *, tree, gimple *, tree[2], int = 0);
class range_query;
extern tree gimple_call_alloc_size (gimple *, wide_int[2] = NULL,
range_query * = NULL);
extern tree gimple_parm_array_size (tree, wide_int[2], bool * = NULL);
extern tree gimple_call_alloc_size (gimple *, wide_int[2] = nullptr,
range_query * = nullptr);
/* Compute the size of an object referenced by the first argument in
a statement given by second argument, using Object Size Type given
by third argument. Store result in an access_ref. */
extern tree compute_objsize (tree, gimple *, int, access_ref *,
range_query * = nullptr);
extern tree compute_objsize (tree, gimple *, int, access_ref *,
pointer_query *);
inline tree compute_objsize (tree ptr, int ostype, access_ref *pref)
{
return compute_objsize (ptr, nullptr, ostype, pref, (range_query *)nullptr);
}
extern tree compute_objsize (tree, int, access_ref *, range_query * = NULL);
/* Legacy/transitional API. Should not be used in new code. */
extern tree compute_objsize (tree, int, access_ref *, pointer_query *);
extern tree compute_objsize (tree, int, tree * = NULL, tree * = NULL,
range_query * = NULL);
extern tree compute_objsize (tree, int, tree * = nullptr, tree * = nullptr,
range_query * = nullptr);
#endif // GCC_POINTER_QUERY_H

View File

@ -260,13 +260,12 @@ T (puts_unlocked, a); // { dg-warning "missing terminating nul" "puts_unlo
// Exerise exec functions.
T (execl, a, s, NULL); // { dg-warning "missing terminating nul" "execl" }
T (execl, a, s, NULL); // { dg-warning "missing terminating nul" "execl" }
T (execle, a, s, NULL, NULL); // { dg-warning "missing terminating nul" "execl" }
T (execlp, a, s, NULL); // { dg-warning "missing terminating nul" "execl" }
T (execle, a, s, NULL, NULL); // { dg-warning "missing terminating nul" "execle" }
T (execlp, a, s, NULL); // { dg-warning "missing terminating nul" "execlp" }
T (execv, a, &d); // { dg-warning "missing terminating nul" "execl" }
T (execve, a, &d, &d); // { dg-warning "missing terminating nul" "execl" }
T (execvp, a, &d); // { dg-warning "missing terminating nul" "execl" }
T (execv, a, &d); // { dg-warning "missing terminating nul" "execv" }
T (execve, a, &d, &d); // { dg-warning "missing terminating nul" "execve" }
T (execvp, a, &d); // { dg-warning "missing terminating nul" "execvp" }
T (gettext, a); // { dg-warning "missing terminating nul" "gettext" }

View File

@ -0,0 +1,38 @@
/* Verify that -Wstringop-overflow uses context-sensitive range info
even at -O0.
{ dg-do compile }
{ dg-options "-O0 -Wall" } */
extern void* memset (void*, int, __SIZE_TYPE__);
char a[8];
void warn_offset_range (int i)
{
if (i < 4)
i = 4;
memset (a + i, 0, 5); // { dg-warning "writing 5 bytes into a region of size 4 " }
}
void warn_size_range (int i, int n)
{
if (n < 5)
n = 5;
memset (a + 4, 1, n); // { dg-warning "writing between 5 and \\d+ bytes into a region of size 4 " }
}
void warn_offset_and_size_range (int i, int n)
{
if (n < 5)
n = 5;
if (i < 4)
{
if (n < 9)
n = 9;
memset (a + i, 1, n); // { dg-warning "writing between 9 and \\d+ bytes into a region of size 8 " }
}
else
memset (a + i, 0, n); // { dg-warning "writing between 5 and \\d+ bytes into a region of size 4 " }
}

View File

@ -1833,7 +1833,7 @@ strlen_pass::adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
tree dst = gimple_call_arg (last.stmt, 0);
access_ref aref;
tree size = compute_objsize (dst, 1, &aref, &ptr_qry);
tree size = compute_objsize (dst, stmt, 1, &aref, &ptr_qry);
if (size && tree_int_cst_lt (size, len))
return;
}
@ -2035,7 +2035,7 @@ strlen_pass::maybe_warn_overflow (gimple *stmt, bool call_lhs, tree len,
access_ref aref;
/* The size of the destination region (which is smaller than
the destination object for stores at a non-zero offset). */
tree destsize = compute_objsize (dest, ostype, &aref, &ptr_qry);
tree destsize = compute_objsize (dest, stmt, ostype, &aref, &ptr_qry);
if (!destsize)
{
@ -3115,7 +3115,7 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt,
}
access_ref aref;
if (tree dstsize = compute_objsize (dst, 1, &aref, ptr_qry))
if (tree dstsize = compute_objsize (dst, stmt, 1, &aref, ptr_qry))
{
/* The source length is unknown. Try to determine the destination
size and see if it matches the specified bound. If not, bail.
@ -3130,7 +3130,7 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt,
/* Avoid warning for strncpy(a, b, N) calls where the following
equalities hold:
N == sizeof a && N == sizeof b */
if (tree srcsize = compute_objsize (src, 1, &aref, ptr_qry))
if (tree srcsize = compute_objsize (src, stmt, 1, &aref, ptr_qry))
if (wi::to_wide (srcsize) == cntrange[1])
return false;

View File

@ -17,7 +17,7 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-Wno-stringop-overflow" }
// { dg-options "-Wno-stringop-overflow -Wno-stringop-overread" }
// 21.3.3 string capacity

View File

@ -15,7 +15,7 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-fchar8_t" }
// { dg-options "-fchar8_t -Wno-stringop-overread" }
// { dg-do run { target c++17 } }
#include <filesystem>
@ -36,6 +36,7 @@ test01()
p = fs::u8path(u8"\xf0\x9d\x84\x9e");
VERIFY( p.u8string() == u8"\U0001D11E" );
// The following triggers -Wstringop-overread. See PR 102958.
std::u8string s1 = u8"filename2";
p = fs::u8path(s1);
VERIFY( p.u8string() == u8"filename2" );