aboutsummaryrefslogtreecommitdiff
path: root/gcc/calls.c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2021-08-17 14:49:05 -0600
committerMartin Sebor <msebor@redhat.com>2021-08-17 14:49:05 -0600
commitb48d4e6818674898f90d9358378c127511ef0f9f (patch)
tree8a9ba017b48f620474808116b309ca78335e0a94 /gcc/calls.c
parent32c3a75390623a0470df52af13f78baddd562981 (diff)
downloadgcc-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.c760
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"