diff options
author | Martin Sebor <msebor@redhat.com> | 2021-10-26 14:38:11 -0600 |
---|---|---|
committer | Martin Sebor <msebor@redhat.com> | 2021-10-26 16:53:23 -0600 |
commit | 9a27acc30a34b7854db32eac562306cebac6fa1e (patch) | |
tree | 50aec5b68739f53fc25c813f8ab5c029167141dd /gcc/gimple-ssa-warn-access.cc | |
parent | 88b504b7a8c5affb0ffa97990d22af2b199e36ed (diff) | |
download | gcc-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.cc | 184 |
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; |