aboutsummaryrefslogtreecommitdiff
path: root/gcc/calls.c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2021-08-06 15:29:33 -0600
committerMartin Sebor <msebor@redhat.com>2021-08-06 16:08:36 -0600
commit81d6cdd335ffc60c216a020d5c99306f659377a2 (patch)
treedfc6982f6965e62985d4cc77343c1e26dccebb41 /gcc/calls.c
parent629b5699fb555b30c25ebc0b503e87b470bed076 (diff)
downloadgcc-81d6cdd335ffc60c216a020d5c99306f659377a2.zip
gcc-81d6cdd335ffc60c216a020d5c99306f659377a2.tar.gz
gcc-81d6cdd335ffc60c216a020d5c99306f659377a2.tar.bz2
Move more code to new gimple-ssa-warn-access pass.
gcc/ChangeLog: * builtins.c (expand_builtin_memchr): Move to gimple-ssa-warn-access.cc. (expand_builtin_strcat): Same. (expand_builtin_stpncpy): Same. (expand_builtin_strncat): Same. (check_read_access): Same. (check_memop_access): Same. (expand_builtin_strlen): Move checks to gimple-ssa-warn-access.cc. (expand_builtin_strnlen): Same. (expand_builtin_memcpy): Same. (expand_builtin_memmove): Same. (expand_builtin_mempcpy): Same. (expand_builtin_strcpy): Same. (expand_builtin_strcpy_args): Same. (expand_builtin_stpcpy_1): Same. (expand_builtin_strncpy): Same. (expand_builtin_memset): Same. (expand_builtin_bzero): Same. (expand_builtin_strcmp): Same. (expand_builtin_strncmp): Same. (expand_builtin): Remove handlers. (fold_builtin_strlen): Add a comment. * builtins.h (check_access): Move to gimple-ssa-warn-access.cc. * calls.c (maybe_warn_nonstring_arg): Same. * diagnostic-spec.c (nowarn_spec_t::nowarn_spec_t): Add warning option. * gimple-fold.c (gimple_fold_builtin_strcpy): Pass argument to callee. (gimple_fold_builtin_stpcpy): Same. * gimple-ssa-warn-access.cc (has_location): New function. (get_location): Same. (get_callee_fndecl): Same. (call_nargs): Same. (call_arg): Same. (warn_string_no_nul): Define. (unterminated_array): Same. (check_nul_terminated_array): Same. (maybe_warn_nonstring_arg): Same. (maybe_warn_for_bound): Same. (warn_for_access): Same. (check_access): Same. (check_memop_access): Same. (check_read_access): Same. (warn_dealloc_offset): Use helper functions. (maybe_emit_free_warning): Same. (class pass_waccess): Add members. (check_strcat): New function. (check_strncat): New function. (check_stxcpy): New function. (check_stxncpy): New function. (check_strncmp): New function. (pass_waccess::check_builtin): New function. (pass_waccess::check): Call it. * gimple-ssa-warn-access.h (warn_string_no_nul): Move here from builtins.h. (maybe_warn_for_bound): Same. (check_access): Same. (check_memop_access): Same. (check_read_access): Same. * pointer-query.h (struct access_data): Define a ctor overload. gcc/testsuite/ChangeLog: * c-c++-common/Wsizeof-pointer-memaccess1.c: Also disable -Wstringop-overread. * c-c++-common/attr-nonstring-3.c: Adjust pattern of expected message. * gcc.dg/Warray-bounds-39.c: Add an xfail due to a known bug. * gcc.dg/Wstring-compare-3.c: Also disable -Wstringop-overread. * gcc.dg/attr-nonstring-2.c: Adjust pattern of expected message. * gcc.dg/attr-nonstring-4.c: Same. * gcc.dg/Wstringop-overread-6.c: New test. * gcc.dg/sso-14.c: Fix typos to avoid buffer overflow.
Diffstat (limited to 'gcc/calls.c')
-rw-r--r--gcc/calls.c310
1 files changed, 1 insertions, 309 deletions
diff --git a/gcc/calls.c b/gcc/calls.c
index 795d214..fcb0d6d 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -61,7 +61,7 @@ along with GCC; see the file COPYING3. If not see
#include "attr-fnspec.h"
#include "value-query.h"
#include "pointer-query.h"
-
+#include "gimple-ssa-warn-access.h"
#include "tree-pretty-print.h"
/* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits. */
@@ -1614,314 +1614,6 @@ get_attr_nonstring_decl (tree expr, tree *ref)
return NULL_TREE;
}
-/* 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.*/
-
-bool
-maybe_warn_nonstring_arg (tree fndecl, tree exp)
-{
- if (!fndecl || !fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
- return false;
-
- if (!warn_stringop_overread || warning_suppressed_p (exp, OPT_Wstringop_overread))
- return false;
-
- /* Avoid clearly invalid calls (more checking done below). */
- unsigned nargs = call_expr_nargs (exp);
- if (!nargs)
- return false;
-
- /* The bound argument to a bounded string function like strncpy. */
- tree bound = NULL_TREE;
-
- /* The longest known or possible string argument to one of the comparison
- functions. If the length is less than the bound it is used instead.
- Since the length is only used for warning and not for code generation
- disable strict mode in the calls to get_range_strlen below. */
- tree maxlen = NULL_TREE;
-
- /* It's safe to call "bounded" string functions with a non-string
- argument since the functions provide an explicit bound for this
- purpose. The exception is strncat where the bound may refer to
- either the destination or the source. */
- int fncode = DECL_FUNCTION_CODE (fndecl);
- switch (fncode)
- {
- case BUILT_IN_STRCMP:
- case BUILT_IN_STRNCMP:
- case BUILT_IN_STRNCASECMP:
- {
- /* For these, if one argument refers to one or more of a set
- of string constants or arrays of known size, determine
- the range of their known or possible lengths and use it
- conservatively as the bound for the unbounded function,
- and to adjust the range of the bound of the bounded ones. */
- for (unsigned argno = 0;
- argno < MIN (nargs, 2)
- && !(maxlen && TREE_CODE (maxlen) == INTEGER_CST); argno++)
- {
- tree arg = CALL_EXPR_ARG (exp, argno);
- if (!get_attr_nonstring_decl (arg))
- {
- c_strlen_data lendata = { };
- /* Set MAXBOUND to an arbitrary non-null non-integer
- node as a request to have it set to the length of
- the longest string in a PHI. */
- lendata.maxbound = arg;
- get_range_strlen (arg, &lendata, /* eltsize = */ 1);
- maxlen = lendata.maxbound;
- }
- }
- }
- /* Fall through. */
-
- case BUILT_IN_STRNCAT:
- case BUILT_IN_STPNCPY:
- case BUILT_IN_STRNCPY:
- if (nargs > 2)
- bound = CALL_EXPR_ARG (exp, 2);
- break;
-
- case BUILT_IN_STRNDUP:
- if (nargs > 1)
- bound = CALL_EXPR_ARG (exp, 1);
- break;
-
- case BUILT_IN_STRNLEN:
- {
- tree arg = CALL_EXPR_ARG (exp, 0);
- if (!get_attr_nonstring_decl (arg))
- {
- c_strlen_data lendata = { };
- /* Set MAXBOUND to an arbitrary non-null non-integer
- node as a request to have it set to the length of
- the longest string in a PHI. */
- lendata.maxbound = arg;
- get_range_strlen (arg, &lendata, /* eltsize = */ 1);
- maxlen = lendata.maxbound;
- }
- if (nargs > 1)
- bound = CALL_EXPR_ARG (exp, 1);
- break;
- }
-
- default:
- break;
- }
-
- /* Determine the range of the bound argument (if specified). */
- tree bndrng[2] = { NULL_TREE, NULL_TREE };
- if (bound)
- {
- STRIP_NOPS (bound);
- get_size_range (bound, bndrng);
- }
-
- location_t loc = EXPR_LOCATION (exp);
-
- if (bndrng[0])
- {
- /* 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]))
- warned = warning_at (loc, OPT_Wstringop_overread,
- "%qD specified bound %E "
- "exceeds maximum object size %E",
- fndecl, bndrng[0], maxobjsize);
- else
- warned = warning_at (loc, OPT_Wstringop_overread,
- "%qD specified bound [%E, %E] "
- "exceeds maximum object size %E",
- fndecl, bndrng[0], bndrng[1],
- maxobjsize);
- if (warned)
- suppress_warning (exp, OPT_Wstringop_overread);
-
- return warned;
- }
- }
-
- if (maxlen && !integer_all_onesp (maxlen))
- {
- /* Add one for the nul. */
- maxlen = const_binop (PLUS_EXPR, TREE_TYPE (maxlen), maxlen,
- size_one_node);
-
- if (!bndrng[0])
- {
- /* Conservatively use the upper bound of the lengths for
- both the lower and the upper bound of the operation. */
- bndrng[0] = maxlen;
- bndrng[1] = maxlen;
- bound = void_type_node;
- }
- else if (maxlen)
- {
- /* Replace the bound on the operation with the upper bound
- of the length of the string if the latter is smaller. */
- if (tree_int_cst_lt (maxlen, bndrng[0]))
- bndrng[0] = maxlen;
- else if (tree_int_cst_lt (maxlen, bndrng[1]))
- bndrng[1] = maxlen;
- }
- }
-
- 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
- the argument's maximum length is bounded. */
- function_args_iterator it;
- function_args_iter_init (&it, TREE_TYPE (fndecl));
-
- for (unsigned argno = 0; ; ++argno, function_args_iter_next (&it))
- {
- /* Avoid iterating past the declared argument in a call
- to function declared without a prototype. */
- if (argno >= nargs)
- break;
-
- tree argtype = function_args_iter_cond (&it);
- if (!argtype)
- break;
-
- if (TREE_CODE (argtype) != POINTER_TYPE)
- continue;
-
- argtype = TREE_TYPE (argtype);
-
- if (TREE_CODE (argtype) != INTEGER_TYPE
- || !TYPE_READONLY (argtype))
- continue;
-
- argtype = TYPE_MAIN_VARIANT (argtype);
- if (argtype != char_type_node)
- continue;
-
- tree callarg = CALL_EXPR_ARG (exp, argno);
- if (TREE_CODE (callarg) == ADDR_EXPR)
- callarg = TREE_OPERAND (callarg, 0);
-
- /* See if the destination is declared with attribute "nonstring". */
- tree decl = get_attr_nonstring_decl (callarg);
- if (!decl)
- continue;
-
- /* The maximum number of array elements accessed. */
- offset_int wibnd = 0;
-
- if (argno && fncode == BUILT_IN_STRNCAT)
- {
- /* See if the bound in strncat is derived from the length
- of the strlen of the destination (as it's expected to be).
- If so, reset BOUND and FNCODE to trigger a warning. */
- tree dstarg = CALL_EXPR_ARG (exp, 0);
- if (is_strlen_related_p (dstarg, bound))
- {
- /* The bound applies to the destination, not to the source,
- so reset these to trigger a warning without mentioning
- the bound. */
- bound = NULL;
- fncode = 0;
- }
- else if (bndrng[1])
- /* Use the upper bound of the range for strncat. */
- wibnd = wi::to_offset (bndrng[1]);
- }
- else if (bndrng[0])
- /* Use the lower bound of the range for functions other than
- strncat. */
- wibnd = wi::to_offset (bndrng[0]);
-
- /* Determine the size of the argument array if it is one. */
- offset_int asize = wibnd;
- bool known_size = false;
- tree type = TREE_TYPE (decl);
-
- /* Determine the array size. For arrays of unknown bound and
- pointers reset BOUND to trigger the appropriate warning. */
- if (TREE_CODE (type) == ARRAY_TYPE)
- {
- if (tree arrbnd = TYPE_DOMAIN (type))
- {
- if ((arrbnd = TYPE_MAX_VALUE (arrbnd)))
- {
- asize = wi::to_offset (arrbnd) + 1;
- known_size = true;
- }
- }
- else if (bound == void_type_node)
- bound = NULL_TREE;
- }
- else if (bound == void_type_node)
- bound = NULL_TREE;
-
- /* In a call to strncat with a bound in a range whose lower but
- not upper bound is less than the array size, reset ASIZE to
- be the same as the bound and the other variable to trigger
- the apprpriate warning below. */
- if (fncode == BUILT_IN_STRNCAT
- && bndrng[0] != bndrng[1]
- && wi::ltu_p (wi::to_offset (bndrng[0]), asize)
- && (!known_size
- || wi::ltu_p (asize, wibnd)))
- {
- asize = wibnd;
- bound = NULL_TREE;
- fncode = 0;
- }
-
- bool warned = false;
-
- auto_diagnostic_group d;
- if (wi::ltu_p (asize, wibnd))
- {
- if (bndrng[0] == bndrng[1])
- 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_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_overread,
- "%qD argument %i declared attribute "
- "%<nonstring%> may be smaller than "
- "the specified bound [%E, %E]",
- fndecl, argno + 1, bndrng[0], bndrng[1]);
- }
- else if (fncode == BUILT_IN_STRNCAT)
- ; /* 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_overread,
- "%qD argument %i declared attribute %<nonstring%>",
- fndecl, argno + 1);
-
- if (warned)
- {
- inform (DECL_SOURCE_LOCATION (decl),
- "argument %qD declared here", decl);
- any_arg_warned = true;
- }
- }
-
- if (any_arg_warned)
- suppress_warning (exp, OPT_Wstringop_overread);
-
- return any_arg_warned;
-}
-
/* Issue an error if CALL_EXPR was flagged as requiring
tall-call optimization. */