diff options
author | Martin Sebor <msebor@redhat.com> | 2021-08-06 15:29:33 -0600 |
---|---|---|
committer | Martin Sebor <msebor@redhat.com> | 2021-08-06 16:08:36 -0600 |
commit | 81d6cdd335ffc60c216a020d5c99306f659377a2 (patch) | |
tree | dfc6982f6965e62985d4cc77343c1e26dccebb41 /gcc/calls.c | |
parent | 629b5699fb555b30c25ebc0b503e87b470bed076 (diff) | |
download | gcc-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.c | 310 |
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. */ |