diff options
author | Martin Sebor <msebor@redhat.com> | 2021-08-17 14:49:05 -0600 |
---|---|---|
committer | Martin Sebor <msebor@redhat.com> | 2021-08-17 14:49:05 -0600 |
commit | b48d4e6818674898f90d9358378c127511ef0f9f (patch) | |
tree | 8a9ba017b48f620474808116b309ca78335e0a94 /gcc/calls.c | |
parent | 32c3a75390623a0470df52af13f78baddd562981 (diff) | |
download | gcc-b48d4e6818674898f90d9358378c127511ef0f9f.zip gcc-b48d4e6818674898f90d9358378c127511ef0f9f.tar.gz gcc-b48d4e6818674898f90d9358378c127511ef0f9f.tar.bz2 |
Move more warning code to gimple-ssa-warn-access etc.
Also resolves:
PR middle-end/101854 - Invalid warning -Wstringop-overflow wrong argument
gcc/ChangeLog:
PR middle-end/101854
* builtins.c (expand_builtin_alloca): Move warning code to check_alloca
in gimple-ssa-warn-access.cc.
* calls.c (alloc_max_size): Move code to check_alloca.
(get_size_range): Move to pointer-query.cc.
(maybe_warn_alloc_args_overflow): Move to gimple-ssa-warn-access.cc.
(get_attr_nonstring_decl): Move to tree.c.
(fntype_argno_type): Move to gimple-ssa-warn-access.cc.
(append_attrname): Same.
(maybe_warn_rdwr_sizes): Same.
(initialize_argument_information): Move code to
gimple-ssa-warn-access.cc.
* calls.h (maybe_warn_alloc_args_overflow): Move to
gimple-ssa-warn-access.h.
(get_attr_nonstring_decl): Move to tree.h.
(maybe_warn_nonstring_arg): Move to gimple-ssa-warn-access.h.
(enum size_range_flags): Move to pointer-query.h.
(get_size_range): Same.
* gimple-ssa-warn-access.cc (has_location): Remove unused overload
to avoid Clang -Wunused-function.
(get_size_range): Declare static.
(maybe_emit_free_warning): Rename...
(maybe_check_dealloc_call): ...to this for consistency.
(class pass_waccess): Add members.
(pass_waccess::~pass_waccess): Defined.
(alloc_max_size): Move here from calls.c.
(maybe_warn_alloc_args_overflow): Same.
(check_alloca): New function.
(check_alloc_size_call): New function.
(check_strncat): Handle another warning flag.
(pass_waccess::check_builtin): Handle alloca.
(fntype_argno_type): Move here from calls.c.
(append_attrname): Same.
(maybe_warn_rdwr_sizes): Same.
(pass_waccess::check_call): Define.
(check_nonstring_args): New function.
(pass_waccess::check): Call new member functions.
(pass_waccess::execute): Enable ranger.
* gimple-ssa-warn-access.h (get_size_range): Move here from calls.h.
(maybe_warn_nonstring_arg): Same.
* gimple-ssa-warn-restrict.c: Remove #include.
* pointer-query.cc (get_size_range): Move here from calls.c.
* pointer-query.h (enum size_range_flags): Same.
(get_size_range): Same.
* tree.c (get_attr_nonstring_decl): Move here from calls.c.
* tree.h (get_attr_nonstring_decl): Move here from calls.h.
gcc/testsuite/ChangeLog:
* gcc.dg/attr-alloc_size-5.c: Adjust optimization to -O1.
* gcc.dg/attr-alloc_size-7.c: Use #pragmas to adjust optimization.
* gcc.dg/attr-alloc_size-8.c: Adjust optimization to -O1.
PR middle-end/101854
* gcc.dg/Wstringop-overflow-72.c: New test.
Diffstat (limited to 'gcc/calls.c')
-rw-r--r-- | gcc/calls.c | 760 |
1 files changed, 0 insertions, 760 deletions
diff --git a/gcc/calls.c b/gcc/calls.c index fcb0d6d..e50d3fc 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -17,7 +17,6 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#define INCLUDE_STRING #include "config.h" #include "system.h" #include "coretypes.h" @@ -50,7 +49,6 @@ along with GCC; see the file COPYING3. If not see #include "rtl-iter.h" #include "tree-vrp.h" #include "tree-ssanames.h" -#include "tree-ssa-strlen.h" #include "intl.h" #include "stringpool.h" #include "hash-map.h" @@ -60,8 +58,6 @@ along with GCC; see the file COPYING3. If not see #include "gimple-fold.h" #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. */ @@ -1223,397 +1219,6 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals) } } -/* The limit set by -Walloc-larger-than=. */ -static GTY(()) tree alloc_object_size_limit; - -/* Initialize ALLOC_OBJECT_SIZE_LIMIT based on the -Walloc-size-larger-than= - setting if the option is specified, or to the maximum object size if it - is not. Return the initialized value. */ - -static tree -alloc_max_size (void) -{ - if (alloc_object_size_limit) - return alloc_object_size_limit; - - HOST_WIDE_INT limit = warn_alloc_size_limit; - if (limit == HOST_WIDE_INT_MAX) - limit = tree_to_shwi (TYPE_MAX_VALUE (ptrdiff_type_node)); - - alloc_object_size_limit = build_int_cst (size_type_node, limit); - - return alloc_object_size_limit; -} - -/* Return true when EXP's range can be determined and set RANGE[] to it - after adjusting it if necessary to make EXP a represents a valid size - of object, or a valid size argument to an allocation function declared - with attribute alloc_size (whose argument may be signed), or to a string - manipulation function like memset. - When ALLOW_ZERO is set in FLAGS, allow returning a range of [0, 0] for - a size in an anti-range [1, N] where N > PTRDIFF_MAX. A zero range is - a (nearly) invalid argument to allocation functions like malloc but it - is a valid argument to functions like memset. - When USE_LARGEST is set in FLAGS set RANGE to the largest valid subrange - in a multi-range, otherwise to the smallest valid subrange. */ - -bool -get_size_range (range_query *query, tree exp, gimple *stmt, tree range[2], - int flags /* = 0 */) -{ - if (!exp) - return false; - - if (tree_fits_uhwi_p (exp)) - { - /* EXP is a constant. */ - range[0] = range[1] = exp; - return true; - } - - tree exptype = TREE_TYPE (exp); - bool integral = INTEGRAL_TYPE_P (exptype); - - wide_int min, max; - enum value_range_kind range_type; - - if (!query) - query = get_global_range_query (); - - if (integral) - { - value_range vr; - - query->range_of_expr (vr, exp, stmt); - - if (vr.undefined_p ()) - vr.set_varying (TREE_TYPE (exp)); - range_type = vr.kind (); - min = wi::to_wide (vr.min ()); - max = wi::to_wide (vr.max ()); - } - else - range_type = VR_VARYING; - - if (range_type == VR_VARYING) - { - if (integral) - { - /* Use the full range of the type of the expression when - no value range information is available. */ - range[0] = TYPE_MIN_VALUE (exptype); - range[1] = TYPE_MAX_VALUE (exptype); - return true; - } - - range[0] = NULL_TREE; - range[1] = NULL_TREE; - return false; - } - - unsigned expprec = TYPE_PRECISION (exptype); - - bool signed_p = !TYPE_UNSIGNED (exptype); - - if (range_type == VR_ANTI_RANGE) - { - if (signed_p) - { - if (wi::les_p (max, 0)) - { - /* EXP is not in a strictly negative range. That means - it must be in some (not necessarily strictly) positive - range which includes zero. Since in signed to unsigned - conversions negative values end up converted to large - positive values, and otherwise they are not valid sizes, - the resulting range is in both cases [0, TYPE_MAX]. */ - min = wi::zero (expprec); - max = wi::to_wide (TYPE_MAX_VALUE (exptype)); - } - else if (wi::les_p (min - 1, 0)) - { - /* EXP is not in a negative-positive range. That means EXP - is either negative, or greater than max. Since negative - sizes are invalid make the range [MAX + 1, TYPE_MAX]. */ - min = max + 1; - max = wi::to_wide (TYPE_MAX_VALUE (exptype)); - } - else - { - max = min - 1; - min = wi::zero (expprec); - } - } - else - { - wide_int maxsize = wi::to_wide (max_object_size ()); - min = wide_int::from (min, maxsize.get_precision (), UNSIGNED); - max = wide_int::from (max, maxsize.get_precision (), UNSIGNED); - if (wi::eq_p (0, min - 1)) - { - /* EXP is unsigned and not in the range [1, MAX]. That means - it's either zero or greater than MAX. Even though 0 would - normally be detected by -Walloc-zero, unless ALLOW_ZERO - is set, set the range to [MAX, TYPE_MAX] so that when MAX - is greater than the limit the whole range is diagnosed. */ - wide_int maxsize = wi::to_wide (max_object_size ()); - if (flags & SR_ALLOW_ZERO) - { - if (wi::leu_p (maxsize, max + 1) - || !(flags & SR_USE_LARGEST)) - min = max = wi::zero (expprec); - else - { - min = max + 1; - max = wi::to_wide (TYPE_MAX_VALUE (exptype)); - } - } - else - { - min = max + 1; - max = wi::to_wide (TYPE_MAX_VALUE (exptype)); - } - } - else if ((flags & SR_USE_LARGEST) - && wi::ltu_p (max + 1, maxsize)) - { - /* When USE_LARGEST is set and the larger of the two subranges - is a valid size, use it... */ - min = max + 1; - max = maxsize; - } - else - { - /* ...otherwise use the smaller subrange. */ - max = min - 1; - min = wi::zero (expprec); - } - } - } - - range[0] = wide_int_to_tree (exptype, min); - range[1] = wide_int_to_tree (exptype, max); - - return true; -} - -bool -get_size_range (tree exp, tree range[2], int flags /* = 0 */) -{ - return get_size_range (/*query=*/NULL, exp, /*stmt=*/NULL, range, flags); -} - -/* Diagnose a call EXP to function FN decorated with attribute alloc_size - whose argument numbers given by IDX with values given by ARGS exceed - the maximum object size or cause an unsigned oveflow (wrapping) when - multiplied. FN is null when EXP is a call via a function pointer. - When ARGS[0] is null the function does nothing. ARGS[1] may be null - for functions like malloc, and non-null for those like calloc that - are decorated with a two-argument attribute alloc_size. */ - -void -maybe_warn_alloc_args_overflow (tree fn, tree exp, tree args[2], int idx[2]) -{ - /* The range each of the (up to) two arguments is known to be in. */ - tree argrange[2][2] = { { NULL_TREE, NULL_TREE }, { NULL_TREE, NULL_TREE } }; - - /* Maximum object size set by -Walloc-size-larger-than= or SIZE_MAX / 2. */ - tree maxobjsize = alloc_max_size (); - - location_t loc = EXPR_LOCATION (exp); - - tree fntype = fn ? TREE_TYPE (fn) : TREE_TYPE (TREE_TYPE (exp)); - bool warned = false; - - /* Validate each argument individually. */ - for (unsigned i = 0; i != 2 && args[i]; ++i) - { - if (TREE_CODE (args[i]) == INTEGER_CST) - { - argrange[i][0] = args[i]; - argrange[i][1] = args[i]; - - if (tree_int_cst_lt (args[i], integer_zero_node)) - { - warned = warning_at (loc, OPT_Walloc_size_larger_than_, - "argument %i value %qE is negative", - idx[i] + 1, args[i]); - } - else if (integer_zerop (args[i])) - { - /* Avoid issuing -Walloc-zero for allocation functions other - than __builtin_alloca that are declared with attribute - returns_nonnull because there's no portability risk. This - avoids warning for such calls to libiberty's xmalloc and - friends. - Also avoid issuing the warning for calls to function named - "alloca". */ - if (fn && fndecl_built_in_p (fn, BUILT_IN_ALLOCA) - ? IDENTIFIER_LENGTH (DECL_NAME (fn)) != 6 - : !lookup_attribute ("returns_nonnull", - TYPE_ATTRIBUTES (fntype))) - warned = warning_at (loc, OPT_Walloc_zero, - "argument %i value is zero", - idx[i] + 1); - } - else if (tree_int_cst_lt (maxobjsize, args[i])) - { - /* G++ emits calls to ::operator new[](SIZE_MAX) in C++98 - mode and with -fno-exceptions as a way to indicate array - size overflow. There's no good way to detect C++98 here - so avoid diagnosing these calls for all C++ modes. */ - if (i == 0 - && fn - && !args[1] - && lang_GNU_CXX () - && DECL_IS_OPERATOR_NEW_P (fn) - && integer_all_onesp (args[i])) - continue; - - warned = warning_at (loc, OPT_Walloc_size_larger_than_, - "argument %i value %qE exceeds " - "maximum object size %E", - idx[i] + 1, args[i], maxobjsize); - } - } - else if (TREE_CODE (args[i]) == SSA_NAME - && get_size_range (args[i], argrange[i])) - { - /* Verify that the argument's range is not negative (including - upper bound of zero). */ - if (tree_int_cst_lt (argrange[i][0], integer_zero_node) - && tree_int_cst_le (argrange[i][1], integer_zero_node)) - { - warned = warning_at (loc, OPT_Walloc_size_larger_than_, - "argument %i range [%E, %E] is negative", - idx[i] + 1, - argrange[i][0], argrange[i][1]); - } - else if (tree_int_cst_lt (maxobjsize, argrange[i][0])) - { - warned = warning_at (loc, OPT_Walloc_size_larger_than_, - "argument %i range [%E, %E] exceeds " - "maximum object size %E", - idx[i] + 1, - argrange[i][0], argrange[i][1], - maxobjsize); - } - } - } - - if (!argrange[0]) - return; - - /* For a two-argument alloc_size, validate the product of the two - arguments if both of their values or ranges are known. */ - if (!warned && tree_fits_uhwi_p (argrange[0][0]) - && argrange[1][0] && tree_fits_uhwi_p (argrange[1][0]) - && !integer_onep (argrange[0][0]) - && !integer_onep (argrange[1][0])) - { - /* Check for overflow in the product of a function decorated with - attribute alloc_size (X, Y). */ - unsigned szprec = TYPE_PRECISION (size_type_node); - wide_int x = wi::to_wide (argrange[0][0], szprec); - wide_int y = wi::to_wide (argrange[1][0], szprec); - - wi::overflow_type vflow; - wide_int prod = wi::umul (x, y, &vflow); - - if (vflow) - warned = warning_at (loc, OPT_Walloc_size_larger_than_, - "product %<%E * %E%> of arguments %i and %i " - "exceeds %<SIZE_MAX%>", - argrange[0][0], argrange[1][0], - idx[0] + 1, idx[1] + 1); - else if (wi::ltu_p (wi::to_wide (maxobjsize, szprec), prod)) - warned = warning_at (loc, OPT_Walloc_size_larger_than_, - "product %<%E * %E%> of arguments %i and %i " - "exceeds maximum object size %E", - argrange[0][0], argrange[1][0], - idx[0] + 1, idx[1] + 1, - maxobjsize); - - if (warned) - { - /* Print the full range of each of the two arguments to make - it clear when it is, in fact, in a range and not constant. */ - if (argrange[0][0] != argrange [0][1]) - inform (loc, "argument %i in the range [%E, %E]", - idx[0] + 1, argrange[0][0], argrange[0][1]); - if (argrange[1][0] != argrange [1][1]) - inform (loc, "argument %i in the range [%E, %E]", - idx[1] + 1, argrange[1][0], argrange[1][1]); - } - } - - if (warned && fn) - { - location_t fnloc = DECL_SOURCE_LOCATION (fn); - - if (DECL_IS_UNDECLARED_BUILTIN (fn)) - inform (loc, - "in a call to built-in allocation function %qD", fn); - else - inform (fnloc, - "in a call to allocation function %qD declared here", fn); - } -} - -/* If EXPR refers to a character array or pointer declared attribute - nonstring return a decl for that array or pointer and set *REF to - the referenced enclosing object or pointer. Otherwise returns - null. */ - -tree -get_attr_nonstring_decl (tree expr, tree *ref) -{ - tree decl = expr; - tree var = NULL_TREE; - if (TREE_CODE (decl) == SSA_NAME) - { - gimple *def = SSA_NAME_DEF_STMT (decl); - - if (is_gimple_assign (def)) - { - tree_code code = gimple_assign_rhs_code (def); - if (code == ADDR_EXPR - || code == COMPONENT_REF - || code == VAR_DECL) - decl = gimple_assign_rhs1 (def); - } - else - var = SSA_NAME_VAR (decl); - } - - if (TREE_CODE (decl) == ADDR_EXPR) - decl = TREE_OPERAND (decl, 0); - - /* To simplify calling code, store the referenced DECL regardless of - the attribute determined below, but avoid storing the SSA_NAME_VAR - obtained above (it's not useful for dataflow purposes). */ - if (ref) - *ref = decl; - - /* Use the SSA_NAME_VAR that was determined above to see if it's - declared nonstring. Otherwise drill down into the referenced - DECL. */ - if (var) - decl = var; - else if (TREE_CODE (decl) == ARRAY_REF) - decl = TREE_OPERAND (decl, 0); - else if (TREE_CODE (decl) == COMPONENT_REF) - decl = TREE_OPERAND (decl, 1); - else if (TREE_CODE (decl) == MEM_REF) - return get_attr_nonstring_decl (TREE_OPERAND (decl, 0), ref); - - if (DECL_P (decl) - && lookup_attribute ("nonstring", DECL_ATTRIBUTES (decl))) - return decl; - - return NULL_TREE; -} - /* Issue an error if CALL_EXPR was flagged as requiring tall-call optimization. */ @@ -1627,310 +1232,6 @@ maybe_complain_about_tail_call (tree call_expr, const char *reason) error_at (EXPR_LOCATION (call_expr), "cannot tail-call: %s", reason); } -/* Returns the type of the argument ARGNO to function with type FNTYPE - or null when the typoe cannot be determined or no such argument exists. */ - -static tree -fntype_argno_type (tree fntype, unsigned argno) -{ - if (!prototype_p (fntype)) - return NULL_TREE; - - tree argtype; - function_args_iterator it; - FOREACH_FUNCTION_ARGS (fntype, argtype, it) - if (argno-- == 0) - return argtype; - - return NULL_TREE; -} - -/* Helper to append the "human readable" attribute access specification - described by ACCESS to the array ATTRSTR with size STRSIZE. Used in - diagnostics. */ - -static inline void -append_attrname (const std::pair<int, attr_access> &access, - char *attrstr, size_t strsize) -{ - if (access.second.internal_p) - return; - - tree str = access.second.to_external_string (); - gcc_assert (strsize >= (size_t) TREE_STRING_LENGTH (str)); - strcpy (attrstr, TREE_STRING_POINTER (str)); -} - -/* Iterate over attribute access read-only, read-write, and write-only - arguments and diagnose past-the-end accesses and related problems - in the function call EXP. */ - -static void -maybe_warn_rdwr_sizes (rdwr_map *rwm, tree fndecl, tree fntype, tree exp) -{ - auto_diagnostic_group adg; - - /* Set if a warning has been issued for any argument (used to decide - whether to emit an informational note at the end). */ - opt_code opt_warned = N_OPTS; - - /* A string describing the attributes that the warnings issued by this - function apply to. Used to print one informational note per function - call, rather than one per warning. That reduces clutter. */ - char attrstr[80]; - attrstr[0] = 0; - - for (rdwr_map::iterator it = rwm->begin (); it != rwm->end (); ++it) - { - std::pair<int, attr_access> access = *it; - - /* Get the function call arguments corresponding to the attribute's - positional arguments. When both arguments have been specified - there will be two entries in *RWM, one for each. They are - cross-referenced by their respective argument numbers in - ACCESS.PTRARG and ACCESS.SIZARG. */ - const int ptridx = access.second.ptrarg; - const int sizidx = access.second.sizarg; - - gcc_assert (ptridx != -1); - gcc_assert (access.first == ptridx || access.first == sizidx); - - /* The pointer is set to null for the entry corresponding to - the size argument. Skip it. It's handled when the entry - corresponding to the pointer argument comes up. */ - if (!access.second.ptr) - continue; - - tree ptrtype = fntype_argno_type (fntype, ptridx); - tree argtype = TREE_TYPE (ptrtype); - - /* The size of the access by the call. */ - tree access_size; - if (sizidx == -1) - { - /* If only the pointer attribute operand was specified and - not size, set SIZE to the greater of MINSIZE or size of - one element of the pointed to type to detect smaller - objects (null pointers are diagnosed in this case only - if the pointer is also declared with attribute nonnull. */ - if (access.second.minsize - && access.second.minsize != HOST_WIDE_INT_M1U) - access_size = build_int_cstu (sizetype, access.second.minsize); - else - access_size = size_one_node; - } - else - access_size = rwm->get (sizidx)->size; - - /* 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 (access_size, sizrng, true)) - { - char *s0 = print_generic_expr_to_str (sizrng[0]); - if (tree_int_cst_equal (sizrng[0], sizrng[1])) - { - gcc_checking_assert (strlen (s0) < sizeof sizstr); - strcpy (sizstr, s0); - } - else - { - char *s1 = print_generic_expr_to_str (sizrng[1]); - gcc_checking_assert (strlen (s0) + strlen (s1) - < sizeof sizstr - 4); - sprintf (sizstr, "[%s, %s]", s0, s1); - free (s1); - } - free (s0); - } - else - *sizstr = '\0'; - - /* Set if a warning has been issued for the current argument. */ - opt_code arg_warned = no_warning; - location_t loc = EXPR_LOCATION (exp); - tree ptr = access.second.ptr; - if (*sizstr - && tree_int_cst_sgn (sizrng[0]) < 0 - && tree_int_cst_sgn (sizrng[1]) < 0) - { - /* Warn about negative sizes. */ - if (access.second.internal_p) - { - const std::string argtypestr - = access.second.array_as_string (ptrtype); - - if (warning_at (loc, OPT_Wstringop_overflow_, - "bound argument %i value %s is " - "negative for a variable length array " - "argument %i of type %s", - sizidx + 1, sizstr, - ptridx + 1, argtypestr.c_str ())) - arg_warned = OPT_Wstringop_overflow_; - } - else if (warning_at (loc, OPT_Wstringop_overflow_, - "argument %i value %s is negative", - sizidx + 1, sizstr)) - arg_warned = OPT_Wstringop_overflow_; - - if (arg_warned != no_warning) - { - append_attrname (access, attrstr, sizeof attrstr); - /* Remember a warning has been issued and avoid warning - again below for the same attribute. */ - opt_warned = arg_warned; - continue; - } - } - - if (tree_int_cst_sgn (sizrng[0]) >= 0) - { - if (COMPLETE_TYPE_P (argtype)) - { - /* Multiply ACCESS_SIZE by the size of the type the pointer - argument points to. If it's incomplete the size is used - as is. */ - if (tree argsize = TYPE_SIZE_UNIT (argtype)) - if (TREE_CODE (argsize) == INTEGER_CST) - { - const int prec = TYPE_PRECISION (sizetype); - wide_int minsize = wi::to_wide (sizrng[0], prec); - minsize *= wi::to_wide (argsize, prec); - access_size = wide_int_to_tree (sizetype, minsize); - } - } - } - else - access_size = NULL_TREE; - - if (integer_zerop (ptr)) - { - if (sizidx >= 0 && tree_int_cst_sgn (sizrng[0]) > 0) - { - /* Warn about null pointers with positive sizes. This is - different from also declaring the pointer argument with - attribute nonnull when the function accepts null pointers - only when the corresponding size is zero. */ - if (access.second.internal_p) - { - const std::string argtypestr - = access.second.array_as_string (ptrtype); - - if (warning_at (loc, OPT_Wnonnull, - "argument %i of variable length " - "array %s is null but " - "the corresponding bound argument " - "%i value is %s", - ptridx + 1, argtypestr.c_str (), - sizidx + 1, sizstr)) - arg_warned = OPT_Wnonnull; - } - else if (warning_at (loc, OPT_Wnonnull, - "argument %i is null but " - "the corresponding size argument " - "%i value is %s", - ptridx + 1, sizidx + 1, sizstr)) - arg_warned = OPT_Wnonnull; - } - else if (access_size && access.second.static_p) - { - /* Warn about null pointers for [static N] array arguments - but do not warn for ordinary (i.e., nonstatic) arrays. */ - if (warning_at (loc, OPT_Wnonnull, - "argument %i to %<%T[static %E]%> " - "is null where non-null expected", - ptridx + 1, argtype, access_size)) - arg_warned = OPT_Wnonnull; - } - - if (arg_warned != no_warning) - { - append_attrname (access, attrstr, sizeof attrstr); - /* Remember a warning has been issued and avoid warning - again below for the same attribute. */ - opt_warned = OPT_Wnonnull; - continue; - } - } - - access_data data (ptr, 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); - - /* The size of the destination or source object. */ - tree dstsize = NULL_TREE, srcsize = NULL_TREE; - if (access.second.mode == access_read_only - || access.second.mode == access_none) - { - /* For a read-only argument there is no destination. For - no access, set the source as well and differentiate via - the access flag below. */ - srcsize = objsize; - if (access.second.mode == access_read_only - || access.second.mode == access_none) - { - /* For a read-only attribute there is no destination so - clear OBJSIZE. This emits "reading N bytes" kind of - diagnostics instead of the "writing N bytes" kind, - unless MODE is none. */ - objsize = NULL_TREE; - } - } - else - dstsize = objsize; - - /* Clear the no-warning bit in case it was set by check_access - in a prior iteration so that accesses via different arguments - are diagnosed. */ - suppress_warning (exp, OPT_Wstringop_overflow_, false); - access_mode mode = data.mode; - if (mode == access_deferred) - mode = TYPE_READONLY (argtype) ? access_read_only : access_read_write; - check_access (exp, access_size, /*maxread=*/ NULL_TREE, srcsize, - dstsize, mode, &data); - - if (warning_suppressed_p (exp, OPT_Wstringop_overflow_)) - opt_warned = OPT_Wstringop_overflow_; - if (opt_warned != N_OPTS) - { - if (access.second.internal_p) - inform (loc, "referencing argument %u of type %qT", - ptridx + 1, ptrtype); - else - /* If check_access issued a warning above, append the relevant - attribute to the string. */ - append_attrname (access, attrstr, sizeof attrstr); - } - } - - if (*attrstr) - { - if (fndecl) - inform (DECL_SOURCE_LOCATION (fndecl), - "in a call to function %qD declared with attribute %qs", - fndecl, attrstr); - else - inform (EXPR_LOCATION (fndecl), - "in a call with type %qT and attribute %qs", - fntype, attrstr); - } - else if (opt_warned != N_OPTS) - { - if (fndecl) - inform (DECL_SOURCE_LOCATION (fndecl), - "in a call to function %qD", fndecl); - else - inform (EXPR_LOCATION (fndecl), - "in a call with type %qT", fntype); - } - - /* Set the bit in case if was cleared and not set above. */ - if (opt_warned != N_OPTS) - suppress_warning (exp, opt_warned); -} - /* Fill in ARGS_SIZE and ARGS array based on the parameters found in CALL_EXPR EXP. @@ -2030,27 +1331,6 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, bitmap_obstack_release (NULL); - tree fntypeattrs = TYPE_ATTRIBUTES (fntype); - /* Extract attribute alloc_size from the type of the called expression - (which could be a function or a function pointer) and if set, store - the indices of the corresponding arguments in ALLOC_IDX, and then - the actual argument(s) at those indices in ALLOC_ARGS. */ - int alloc_idx[2] = { -1, -1 }; - if (tree alloc_size = lookup_attribute ("alloc_size", fntypeattrs)) - { - tree args = TREE_VALUE (alloc_size); - alloc_idx[0] = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1; - if (TREE_CHAIN (args)) - alloc_idx[1] = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1; - } - - /* Array for up to the two attribute alloc_size arguments. */ - tree alloc_args[] = { NULL_TREE, NULL_TREE }; - - /* Map of attribute accewss specifications for function arguments. */ - rdwr_map rdwr_idx; - init_attr_rdwr_indices (&rdwr_idx, fntypeattrs); - /* I counts args in order (to be) pushed; ARGPOS counts in order written. */ for (argpos = 0; argpos < num_actuals; i--, argpos++) { @@ -2283,44 +1563,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, does pass the promoted mode. */ arg.mode = TYPE_MODE (type); targetm.calls.function_arg_advance (args_so_far, arg); - - /* Store argument values for functions decorated with attribute - alloc_size. */ - if (argpos == alloc_idx[0]) - alloc_args[0] = args[i].tree_value; - else if (argpos == alloc_idx[1]) - alloc_args[1] = args[i].tree_value; - - /* Save the actual argument that corresponds to the access attribute - operand for later processing. */ - if (attr_access *access = rdwr_idx.get (argpos)) - { - if (POINTER_TYPE_P (type)) - { - access->ptr = args[i].tree_value; - // A nonnull ACCESS->SIZE contains VLA bounds. */ - } - else - { - access->size = args[i].tree_value; - gcc_assert (access->ptr == NULL_TREE); - } - } - } - - if (alloc_args[0]) - { - /* Check the arguments of functions decorated with attribute - alloc_size. */ - maybe_warn_alloc_args_overflow (fndecl, exp, alloc_args, alloc_idx); } - - /* Detect passing non-string arguments to functions expecting - nul-terminated strings. */ - maybe_warn_nonstring_arg (fndecl, exp); - - /* Check attribute access arguments. */ - maybe_warn_rdwr_sizes (&rdwr_idx, fndecl, fntype, exp); } /* Update ARGS_SIZE to contain the total size for the argument block. @@ -6020,6 +5263,3 @@ cxx17_empty_base_field_p (const_tree field) && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)) && !lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (field))); } - -/* Tell the garbage collector about GTY markers in this source file. */ -#include "gt-calls.h" |