aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-ssa-warn-access.cc
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2021-10-26 14:38:11 -0600
committerMartin Sebor <msebor@redhat.com>2021-10-26 16:53:23 -0600
commit9a27acc30a34b7854db32eac562306cebac6fa1e (patch)
tree50aec5b68739f53fc25c813f8ab5c029167141dd /gcc/gimple-ssa-warn-access.cc
parent88b504b7a8c5affb0ffa97990d22af2b199e36ed (diff)
downloadgcc-9a27acc30a34b7854db32eac562306cebac6fa1e.zip
gcc-9a27acc30a34b7854db32eac562306cebac6fa1e.tar.gz
gcc-9a27acc30a34b7854db32eac562306cebac6fa1e.tar.bz2
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.
Diffstat (limited to 'gcc/gimple-ssa-warn-access.cc')
-rw-r--r--gcc/gimple-ssa-warn-access.cc184
1 files changed, 99 insertions, 85 deletions
diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index 88a2e72..63fc27a 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -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, 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);
- check_access (stmt, size, /*maxread=*/NULL_TREE,
- srcsize, dstsize, data.mode, &data);
+ 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;