public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] more warning code refactoring
@ 2021-08-17  1:51 Martin Sebor
  2021-08-17  8:51 ` Richard Biener
  0 siblings, 1 reply; 14+ messages in thread
From: Martin Sebor @ 2021-08-17  1:51 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 862 bytes --]

The attached patch continues with the move of warning code from
builtins.c and calls.c into a more suitable home.  As before, it
is mostly free of functional changes.  The one exception is that
as pleasant a side-effect, moving the attribute access checking
from initialize_argument_information() in calls.c to the new
warning pass also happens to fix PR 101854.  This is thanks to
the latter iterating over function arguments explicitly provided
in the program and not having to worry about skipping over
the additional pointer argument synthesized for calls to functions
that return a large struct by value that the former function sneaks
into the argument list.

Tested on x86_64-linux.

Martin

Previous patches in this series:
https://gcc.gnu.org/pipermail/gcc-patches/2021-August/576821.html
https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575377.html

[-- Attachment #2: gcc-101854.diff --]
[-- Type: text/x-patch, Size: 67202 bytes --]

Move more warning code to gimple-ssa-warn-access etc.

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 (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:

	PR middle-end/101854
	* gcc.dg/Wstringop-overflow-72.c: New test.

diff --git a/gcc/builtins.c b/gcc/builtins.c
index d2be807f1d6..99548627761 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -43,7 +43,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "alias.h"
 #include "fold-const.h"
 #include "fold-const-call.h"
-#include "gimple-ssa-warn-restrict.h"
+#include "gimple-ssa-warn-access.h"
 #include "stor-layout.h"
 #include "calls.h"
 #include "varasm.h"
@@ -81,7 +81,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "demangle.h"
 #include "gimple-range.h"
 #include "pointer-query.h"
-#include "gimple-ssa-warn-access.h"
 
 struct target_builtins default_target_builtins;
 #if SWITCHABLE_TARGET
@@ -4896,25 +4895,6 @@ expand_builtin_alloca (tree exp)
   if (!valid_arglist)
     return NULL_RTX;
 
-  if ((alloca_for_var
-       && warn_vla_limit >= HOST_WIDE_INT_MAX
-       && warn_alloc_size_limit < warn_vla_limit)
-      || (!alloca_for_var
-	  && warn_alloca_limit >= HOST_WIDE_INT_MAX
-	  && warn_alloc_size_limit < warn_alloca_limit
-	  ))
-    {
-      /* -Walloca-larger-than and -Wvla-larger-than settings of
-	 less than HOST_WIDE_INT_MAX override the more general
-	 -Walloc-size-larger-than so unless either of the former
-	 options is smaller than the last one (wchich would imply
-	 that the call was already checked), check the alloca
-	 arguments for overflow.  */
-      tree args[] = { CALL_EXPR_ARG (exp, 0), NULL_TREE };
-      int idx[] = { 0, -1 };
-      maybe_warn_alloc_args_overflow (fndecl, exp, args, idx);
-    }
-
   /* Compute the argument.  */
   op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
 
diff --git a/gcc/calls.c b/gcc/calls.c
index fcb0d6dec69..e50d3fc3b62 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"
diff --git a/gcc/calls.h b/gcc/calls.h
index 4a018f6ae85..9a98f5de75f 100644
--- a/gcc/calls.h
+++ b/gcc/calls.h
@@ -130,21 +130,8 @@ extern bool apply_pass_by_reference_rules (CUMULATIVE_ARGS *,
 					   function_arg_info &);
 extern bool reference_callee_copied (CUMULATIVE_ARGS *,
 				     const function_arg_info &);
-extern void maybe_warn_alloc_args_overflow (tree, tree, tree[2], int[2]);
-extern tree get_attr_nonstring_decl (tree, tree * = NULL);
-extern bool maybe_warn_nonstring_arg (tree, tree);
 extern void maybe_complain_about_tail_call (tree, const char *);
-enum size_range_flags
-  {
-   /* Set to consider zero a valid range.  */
-   SR_ALLOW_ZERO = 1,
-   /* Set to use the largest subrange of a set of ranges as opposed
-      to the smallest.  */
-   SR_USE_LARGEST = 2
-  };
-extern bool get_size_range (tree, tree[2], int = 0);
-extern bool get_size_range (class range_query *, tree, gimple *,
-			    tree[2], int = 0);
+
 extern rtx rtx_for_static_chain (const_tree, bool);
 extern bool cxx17_empty_base_field_p (const_tree);
 
diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index 93f43b711e2..81c6562c518 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -20,6 +20,7 @@
    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"
@@ -36,6 +37,7 @@
 #include "fold-const.h"
 #include "gimple-fold.h"
 #include "gimple-iterator.h"
+#include "langhooks.h"
 #include "tree-dfa.h"
 #include "tree-ssa.h"
 #include "tree-cfg.h"
@@ -1177,7 +1179,7 @@ warn_for_access (location_t loc, tree func, tree expr, int opt,
 /* Helper to set RANGE to the range of BOUND if it's nonnull, bounded
    by BNDRNG if nonnull and valid.  */
 
-void
+static void
 get_size_range (tree bound, tree range[2], const offset_int bndrng[2])
 {
   if (bound)
@@ -2105,14 +2107,14 @@ warn_dealloc_offset (location_t loc, gimple *call, const access_ref &aref)
    form of C++ operatorn new.  */
 
 static void
-maybe_emit_free_warning (gcall *call)
+maybe_check_dealloc_call (gcall *call)
 {
   tree fndecl = gimple_call_fndecl (call);
   if (!fndecl)
     return;
 
   unsigned argno = fndecl_dealloc_argno (fndecl);
-  if ((unsigned) gimple_call_num_args (call) <= argno)
+  if ((unsigned) call_nargs (call) <= argno)
     return;
 
   tree ptr = gimple_call_arg (call, argno);
@@ -2247,9 +2249,13 @@ class pass_waccess : public gimple_opt_pass
 {
  public:
   pass_waccess (gcc::context *ctxt)
-    : gimple_opt_pass (pass_data_waccess, ctxt), m_ranger ()
+    : gimple_opt_pass (pass_data_waccess, ctxt),
+      ptr_qry (m_ranger, &var_cache),
+      m_ranger ()
     { }
 
+  ~pass_waccess ();
+
   opt_pass *clone () { return new pass_waccess (m_ctxt); }
 
   virtual bool gate (function *);
@@ -2258,6 +2264,9 @@ class pass_waccess : public gimple_opt_pass
   /* Check a call to a built-in function.  */
   bool check_builtin (gcall *);
 
+  /* Check a call to an ordinary function.  */
+  bool check_call (gcall *);
+
   /* Check statements in a basic block.  */
   void check (basic_block);
 
@@ -2265,9 +2274,21 @@ class pass_waccess : public gimple_opt_pass
  void check (gcall *);
 
 private:
+  /* A pointer_query object and its cache to store information about
+     pointers and their targets in.  */
+  pointer_query ptr_qry;
+  pointer_query::cache_type var_cache;
+
   gimple_ranger *m_ranger;
 };
 
+/* Release pointer_query cache.  */
+
+pass_waccess::~pass_waccess ()
+{
+  ptr_qry.flush_cache ();
+}
+
 /* Return true when any checks performed by the pass are enabled.  */
 
 bool
@@ -2278,6 +2299,235 @@ pass_waccess::gate (function *)
 	  || warn_mismatched_new_delete);
 }
 
+/* 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)
+{
+  HOST_WIDE_INT limit = warn_alloc_size_limit;
+  if (limit == HOST_WIDE_INT_MAX)
+    limit = tree_to_shwi (TYPE_MAX_VALUE (ptrdiff_type_node));
+
+  return build_int_cst (size_type_node, limit);
+}
+
+/* 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 (gimple *stmt, const tree args[2],
+				const 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 = get_location (stmt);
+
+  tree fn = gimple_call_fndecl (stmt);
+  tree fntype = fn ? TREE_TYPE (fn) : gimple_call_fntype (stmt);
+  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);
+    }
+}
+
+/* Check a call to an alloca function for an excessive size.  */
+
+static void
+check_alloca (gimple *stmt)
+{
+  if ((warn_vla_limit >= HOST_WIDE_INT_MAX
+       && warn_alloc_size_limit < warn_vla_limit)
+      || (warn_alloca_limit >= HOST_WIDE_INT_MAX
+	  && warn_alloc_size_limit < warn_alloca_limit))
+    {
+      /* -Walloca-larger-than and -Wvla-larger-than settings of less
+	 than  HWI_MAX override the more general -Walloc-size-larger-than
+	 so unless either of the former options is smaller than the last
+	 one (wchich would imply that the call was already checked), check
+	 the alloca arguments for overflow.  */
+      const tree alloc_args[] = { call_arg (stmt, 0), NULL_TREE };
+      const int idx[] = { 0, -1 };
+      maybe_warn_alloc_args_overflow (stmt, alloc_args, idx);
+    }
+}
+
+/* Check a call to an allocation function for an excessive size.  */
+
+static void
+check_alloc_size_call (gimple *stmt)
+{
+  if (gimple_call_num_args (stmt) < 1)
+    /* Avoid invalid calls to functions without a prototype.  */
+    return;
+
+  tree fntype = gimple_call_fntype (stmt);
+  tree fntypeattrs = TYPE_ATTRIBUTES (fntype);
+
+  tree alloc_size = lookup_attribute ("alloc_size", fntypeattrs);
+  if (!alloc_size)
+    return;
+
+  /* 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 idx[2] = { -1, -1 };
+  tree alloc_args[] = { NULL_TREE, NULL_TREE };
+
+  tree args = TREE_VALUE (alloc_size);
+  idx[0] = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1;
+  alloc_args[0] = call_arg (stmt, idx[0]);
+  if (TREE_CHAIN (args))
+    {
+      idx[1] = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1;
+      alloc_args[1] = call_arg (stmt, idx[1]);
+    }
+
+  maybe_warn_alloc_args_overflow (stmt, alloc_args, idx);
+}
+
 /* Check a call STMT to strcat() for overflow and warn if it does.  */
 
 static void
@@ -2308,7 +2558,7 @@ check_strcat (gimple *stmt)
 static void
 check_strncat (gimple *stmt)
 {
-  if (!warn_stringop_overflow)
+  if (!warn_stringop_overflow && !warn_stringop_overread)
     return;
 
   tree dest = call_arg (stmt, 0);
@@ -2537,6 +2787,12 @@ pass_waccess::check_builtin (gcall *stmt)
 
   switch (DECL_FUNCTION_CODE (callee))
     {
+    case BUILT_IN_ALLOCA:
+    case BUILT_IN_ALLOCA_WITH_ALIGN:
+    case BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX:
+      check_alloca (stmt);
+      return true;
+
     case BUILT_IN_GETTEXT:
     case BUILT_IN_PUTS:
     case BUILT_IN_PUTS_UNLOCKED:
@@ -2639,6 +2895,370 @@ pass_waccess::check_builtin (gcall *stmt)
   return true;
 }
 
+/* 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, gimple *stmt)
+{
+  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 = no_warning;
+
+  /* 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 = get_location (stmt);
+      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 (stmt, 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 (stmt, access_size, /*maxread=*/ NULL_TREE, srcsize,
+		    dstsize, mode, &data);
+
+      if (warning_suppressed_p (stmt, OPT_Wstringop_overflow_))
+	opt_warned = OPT_Wstringop_overflow_;
+      if (opt_warned != no_warning)
+	{
+	  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 (get_location (fndecl),
+		"in a call to function %qD declared with attribute %qs",
+		fndecl, attrstr);
+      else
+	inform (get_location (stmt),
+		"in a call with type %qT and attribute %qs",
+		fntype, attrstr);
+    }
+  else if (opt_warned != no_warning)
+    {
+      if (fndecl)
+	inform (get_location (fndecl),
+		"in a call to function %qD", fndecl);
+      else
+	inform (get_location (stmt),
+		"in a call with type %qT", fntype);
+    }
+
+  /* Set the bit in case if was cleared and not set above.  */
+  if (opt_warned != no_warning)
+    suppress_warning (stmt, opt_warned);
+}
+
+/* Check call STMT to an ordinary (non-built-in) function for invalid
+   accesses.  Return true if a call has been handled.  */
+
+bool
+pass_waccess::check_call (gcall *stmt)
+{
+  tree fntype = gimple_call_fntype (stmt);
+  if (!fntype)
+    return false;
+
+  tree fntypeattrs = TYPE_ATTRIBUTES (fntype);
+  if (!fntypeattrs)
+    return false;
+
+  /* Map of attribute accewss specifications for function arguments.  */
+  rdwr_map rdwr_idx;
+  init_attr_rdwr_indices (&rdwr_idx, fntypeattrs);
+
+  unsigned nargs = call_nargs (stmt);
+  for (unsigned i = 0; i != nargs; ++i)
+    {
+      tree arg = call_arg (stmt, i);
+
+      /* Save the actual argument that corresponds to the access attribute
+	 operand for later processing.  */
+      if (attr_access *access = rdwr_idx.get (i))
+	{
+	  if (POINTER_TYPE_P (TREE_TYPE (arg)))
+	    {
+	      access->ptr = arg;
+	      // A nonnull ACCESS->SIZE contains VLA bounds.  */
+	    }
+	  else
+	    {
+	      access->size = arg;
+	      gcc_assert (access->ptr == NULL_TREE);
+	    }
+	}
+    }
+
+  /* Check attribute access arguments.  */
+  tree fndecl = gimple_call_fndecl (stmt);
+  maybe_warn_rdwr_sizes (&rdwr_idx, fndecl, fntype, stmt);
+
+  check_alloc_size_call (stmt);
+  return true;
+}
+
+/* Check arguments in a call STMT for attribute nonstring.  */
+
+static void
+check_nonstring_args (gcall *stmt)
+{
+  tree fndecl = gimple_call_fndecl (stmt);
+
+  /* Detect passing non-string arguments to functions expecting
+     nul-terminated strings.  */
+  maybe_warn_nonstring_arg (fndecl, stmt);
+}
+
 /* Check call STMT for invalid accesses.  */
 
 void
@@ -2648,7 +3268,12 @@ pass_waccess::check (gcall *stmt)
       && check_builtin (stmt))
     return;
 
-  maybe_emit_free_warning (stmt);
+  if (is_gimple_call (stmt))
+    check_call (stmt);
+
+  maybe_check_dealloc_call (stmt);
+
+  check_nonstring_args (stmt);
 }
 
 /* Check basic block BB for invalid accesses.  */
@@ -2669,6 +3294,8 @@ pass_waccess::check (basic_block bb)
 unsigned
 pass_waccess::execute (function *fun)
 {
+  m_ranger = enable_ranger (cfun);
+
   basic_block bb;
   FOR_EACH_BB_FN (bb, fun)
     check (bb);
diff --git a/gcc/gimple-ssa-warn-access.h b/gcc/gimple-ssa-warn-access.h
index 8b33ecbd4fb..1cd3a28c421 100644
--- a/gcc/gimple-ssa-warn-access.h
+++ b/gcc/gimple-ssa-warn-access.h
@@ -31,7 +31,9 @@ extern void warn_string_no_nul (location_t, tree, const char *, tree,
 				tree, tree = NULL_TREE, bool = false,
 				const wide_int[2] = NULL);
 extern tree unterminated_array (tree, tree * = NULL, bool * = NULL);
-extern void get_size_range (tree, tree[2], const offset_int[2]);
+
+extern bool maybe_warn_nonstring_arg (tree, gimple *);
+extern bool maybe_warn_nonstring_arg (tree, tree);
 
 class access_data;
 extern bool maybe_warn_for_bound (opt_code, location_t, gimple *, tree,
diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c
index 404acb03195..d1df9ca8d4f 100644
--- a/gcc/gimple-ssa-warn-restrict.c
+++ b/gcc/gimple-ssa-warn-restrict.c
@@ -29,6 +29,7 @@
 #include "pointer-query.h"
 #include "ssa.h"
 #include "gimple-pretty-print.h"
+#include "gimple-ssa-warn-access.h"
 #include "gimple-ssa-warn-restrict.h"
 #include "diagnostic-core.h"
 #include "fold-const.h"
diff --git a/gcc/pointer-query.cc b/gcc/pointer-query.cc
index bc7cac092f5..99caf78bfa7 100644
--- a/gcc/pointer-query.cc
+++ b/gcc/pointer-query.cc
@@ -22,58 +22,21 @@
 #include "system.h"
 #include "coretypes.h"
 #include "backend.h"
-#include "target.h"
-#include "rtl.h"
 #include "tree.h"
-#include "memmodel.h"
 #include "gimple.h"
-#include "predict.h"
-#include "tm_p.h"
 #include "stringpool.h"
 #include "tree-vrp.h"
-#include "tree-ssanames.h"
-#include "expmed.h"
-#include "optabs.h"
-#include "emit-rtl.h"
-#include "recog.h"
 #include "diagnostic-core.h"
-#include "alias.h"
 #include "fold-const.h"
-#include "fold-const-call.h"
-#include "gimple-ssa-warn-restrict.h"
-#include "stor-layout.h"
-#include "calls.h"
-#include "varasm.h"
 #include "tree-object-size.h"
 #include "tree-ssa-strlen.h"
-#include "realmpfr.h"
-#include "cfgrtl.h"
-#include "except.h"
-#include "dojump.h"
-#include "explow.h"
-#include "stmt.h"
-#include "expr.h"
-#include "libfuncs.h"
-#include "output.h"
-#include "typeclass.h"
 #include "langhooks.h"
-#include "value-prof.h"
-#include "builtins.h"
 #include "stringpool.h"
 #include "attribs.h"
-#include "asan.h"
-#include "internal-fn.h"
-#include "case-cfn-macros.h"
 #include "gimple-fold.h"
 #include "intl.h"
-#include "tree-dfa.h"
-#include "gimple-iterator.h"
-#include "gimple-ssa.h"
-#include "tree-ssa-live.h"
-#include "tree-outof-ssa.h"
 #include "attr-fnspec.h"
 #include "gimple-range.h"
-
 #include "pointer-query.h"
 
 static bool compute_objsize_r (tree, int, access_ref *, ssa_name_limit_t &,
@@ -311,6 +274,164 @@ gimple_call_return_array (gimple *stmt, offset_int offrng[2], bool *past_end,
   return NULL_TREE;
 }
 
+/* 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);
+}
+
 /* If STMT is a call to an allocation function, returns the constant
    maximum size of the object allocated by the call represented as
    sizetype.  If nonnull, sets RNG1[] to the range of the size.
diff --git a/gcc/pointer-query.h b/gcc/pointer-query.h
index 8bd538a3ac2..eb7e90dde03 100644
--- a/gcc/pointer-query.h
+++ b/gcc/pointer-query.h
@@ -230,6 +230,17 @@ struct access_data
   access_mode mode;
 };
 
+enum size_range_flags
+  {
+   /* Set to consider zero a valid range.  */
+   SR_ALLOW_ZERO = 1,
+   /* Set to use the largest subrange of a set of ranges as opposed
+      to the smallest.  */
+   SR_USE_LARGEST = 2
+  };
+extern bool get_size_range (tree, tree[2], int = 0);
+extern bool get_size_range (range_query *, tree, gimple *, tree[2], int = 0);
+
 class range_query;
 extern tree gimple_call_alloc_size (gimple *, wide_int[2] = NULL,
 				    range_query * = NULL);
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-72.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-72.c
new file mode 100644
index 00000000000..c10773e90a3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-72.c
@@ -0,0 +1,13 @@
+/* PR middle-end/101854 - Invalid warning -Wstringop-overflow wrong argument
+   { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+struct A { int a[5]; };
+
+struct A g (int*, int[6][8]);
+
+struct A f (void)
+{
+  int a[2];
+  return g (a, 0);            // { dg-bogus "-Wstringop-overflow" }
+}
diff --git a/gcc/tree.c b/gcc/tree.c
index 6ec8a9738c8..cba3bca41b3 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -14464,6 +14464,60 @@ fndecl_dealloc_argno (tree fndecl)
   return UINT_MAX;
 }
 
+/* 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 return
+   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;
+}
+
 #if CHECKING_P
 
 namespace selftest {
diff --git a/gcc/tree.h b/gcc/tree.h
index a26500dca61..76476a1857d 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -6485,4 +6485,10 @@ extern void copy_warning (tree, const_tree);
    value if it isn't.  */
 extern unsigned fndecl_dealloc_argno (tree);
 
+/* If an expression refers to a character array or pointer declared
+   attribute nonstring, return a decl for that array or pointer and
+   if nonnull, set the second argument to the referenced enclosing
+   object or pointer.  Otherwise return null.  */
+extern tree get_attr_nonstring_decl (tree, tree * = NULL);
+
 #endif  /* GCC_TREE_H  */

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] more warning code refactoring
  2021-08-17  1:51 [PATCH] more warning code refactoring Martin Sebor
@ 2021-08-17  8:51 ` Richard Biener
  2021-08-17 21:09   ` Martin Sebor
  0 siblings, 1 reply; 14+ messages in thread
From: Richard Biener @ 2021-08-17  8:51 UTC (permalink / raw)
  To: Martin Sebor; +Cc: gcc-patches

On Tue, Aug 17, 2021 at 3:52 AM Martin Sebor via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> The attached patch continues with the move of warning code from
> builtins.c and calls.c into a more suitable home.  As before, it
> is mostly free of functional changes.  The one exception is that
> as pleasant a side-effect, moving the attribute access checking
> from initialize_argument_information() in calls.c to the new
> warning pass also happens to fix PR 101854.  This is thanks to
> the latter iterating over function arguments explicitly provided
> in the program and not having to worry about skipping over
> the additional pointer argument synthesized for calls to functions
> that return a large struct by value that the former function sneaks
> into the argument list.
>
> Tested on x86_64-linux.

OK.

Thanks,
Richard.

> Martin
>
> Previous patches in this series:
> https://gcc.gnu.org/pipermail/gcc-patches/2021-August/576821.html
> https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575377.html

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] more warning code refactoring
  2021-08-17  8:51 ` Richard Biener
@ 2021-08-17 21:09   ` Martin Sebor
  0 siblings, 0 replies; 14+ messages in thread
From: Martin Sebor @ 2021-08-17 21:09 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches

On 8/17/21 2:51 AM, Richard Biener wrote:
> On Tue, Aug 17, 2021 at 3:52 AM Martin Sebor via Gcc-patches
> <gcc-patches@gcc.gnu.org> wrote:
>>
>> The attached patch continues with the move of warning code from
>> builtins.c and calls.c into a more suitable home.  As before, it
>> is mostly free of functional changes.  The one exception is that
>> as pleasant a side-effect, moving the attribute access checking
>> from initialize_argument_information() in calls.c to the new
>> warning pass also happens to fix PR 101854.  This is thanks to
>> the latter iterating over function arguments explicitly provided
>> in the program and not having to worry about skipping over
>> the additional pointer argument synthesized for calls to functions
>> that return a large struct by value that the former function sneaks
>> into the argument list.
>>
>> Tested on x86_64-linux.
> 
> OK.

Jit testing exposed a bug due to an uninitialized variable (oddly
tests for no other front end did so).  I fixed it and (after
retesting the result) committed r12-2976.

Thanks
Martin

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] more warning code refactoring
  2021-08-20  1:38       ` Kewen.Lin
@ 2021-08-20 14:49         ` Martin Sebor
  0 siblings, 0 replies; 14+ messages in thread
From: Martin Sebor @ 2021-08-20 14:49 UTC (permalink / raw)
  To: Kewen.Lin; +Cc: GCC Patches, David Edelsohn

On 8/19/21 7:38 PM, Kewen.Lin wrote:
> Hi Martin,
> 
> on 2021/8/20 上午12:30, Martin Sebor wrote:
>> On 8/19/21 9:03 AM, Martin Sebor wrote:
>>> On 8/18/21 11:56 PM, Kewen.Lin wrote:
>>>> Hi David,
>>>>
>>>> on 2021/8/19 上午11:26, David Edelsohn via Gcc-patches wrote:
>>>>> Hi, Martin
>>>>>
>>>>> A few PowerPC-specific testcases started failing yesterday on AIX with
>>>>> a strange failure mode: the compiler runs out of memory.  As you may
>>>>> expect from telling you this in an email reply to your patch, I have
>>>>> bisected the failure and landed on your commit.  I can alternate
>>>>> between the previous commit and your commit, and the failure
>>>>> definitely appears with your patch, although I'm unsure how your patch
>>>>> affected memory allocation in the compiler.  Maybe moving the code
>>>>> changed a type of allocation or some memory no longer is being freed?
>>>>>
>>>>
>>>>
>>>> To get rid of GTY variable alloc_object_size_limit looks suspicious,
>>>> maybe tree objects returned by alloc_max_size after the change are out
>>>> of GC's tracking?
>>>>
>>>> If the suspicion holds, the attached explorative diff may help.
>>>
>>> I wouldn't expect that to make a difference.  There are thousands
>>> of similar calls to build_int_cst() throughout the middle end.
>>>
>>> Looking at the original patch, the change that I'm not sure about
>>> and that shouldn't have been part of the refactoring is the call
>>> to enable_ranger() in pass_waccess::execute().  It's something
>>> I was planning to do next.  But even that I wouldn't expect to
>>> eat up a whole 1GB or memory.
>>
>> I have reproduced the excessive memory consumption with
>> the rlwimi-0.c test and a powerpc-linux cross-compiler, and
>> confirmed that it is indeed caused by the call to enable_ranger().
>> The test defines some six thousand functions so it seems that
>> unless each call enable_ranger() is paired with some call to
>> release the memory it allocates the memory leaks.
>>
>> The removal of the alloc_object_size_limit global variable doesn't
>> have any effect on the test case.  The function that used it (and
>> now calls build_int_cst () instead) isn't called when the test
>> is compiled  (It's only called for calls to allocation functions
>> in the source and the test case has none.
>>
> 
> Thanks for the clarification and sorry for noisy suspicion!

No worries.  It was a reasonable first guess.

Martin

> 
> BR,
> Kewen
> 
>> Let me take care of releasing the ranger memory.
>>
>> Martin
>>
>>
>>>
>>>>
>>>> BR,
>>>> Kewen
>>>>
>>>>> Previously, compiler bootstrap and all testcases ran with a data size
>>>>> of 1GB.  After your change, the data size required for those
>>>>> particular testcases jumped to 2GB.
>>>>>
>>>>> The testcases are
>>>>>
>>>>> gcc/testsuite/gcc.target/powerpc/rlwimi-[012].c
>>>>>
>>>>> The failure is
>>>>>
>>>>> cc1: out of memory allocating 65536 bytes after a total of 1608979296
>>>>>
>>>>> This seems like a significant memory use regression.  Any ideas what happened?
>>>
>>> Not really.  The patch just moved code around.  I didn't make any
>>> changes that I'd expect to impact memory allocation to an appreciable
>>> extent, at least not intentionally.  Let me look into it and get back
>>> to you.
>>>
>>> Martin
>>>
>>>>>
>>>>> Thanks, David
>>>>>
>>>
>>
> 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] more warning code refactoring
  2021-08-19 16:30     ` Martin Sebor
@ 2021-08-20  1:38       ` Kewen.Lin
  2021-08-20 14:49         ` Martin Sebor
  0 siblings, 1 reply; 14+ messages in thread
From: Kewen.Lin @ 2021-08-20  1:38 UTC (permalink / raw)
  To: Martin Sebor; +Cc: GCC Patches, David Edelsohn

Hi Martin,

on 2021/8/20 上午12:30, Martin Sebor wrote:
> On 8/19/21 9:03 AM, Martin Sebor wrote:
>> On 8/18/21 11:56 PM, Kewen.Lin wrote:
>>> Hi David,
>>>
>>> on 2021/8/19 上午11:26, David Edelsohn via Gcc-patches wrote:
>>>> Hi, Martin
>>>>
>>>> A few PowerPC-specific testcases started failing yesterday on AIX with
>>>> a strange failure mode: the compiler runs out of memory.  As you may
>>>> expect from telling you this in an email reply to your patch, I have
>>>> bisected the failure and landed on your commit.  I can alternate
>>>> between the previous commit and your commit, and the failure
>>>> definitely appears with your patch, although I'm unsure how your patch
>>>> affected memory allocation in the compiler.  Maybe moving the code
>>>> changed a type of allocation or some memory no longer is being freed?
>>>>
>>>
>>>
>>> To get rid of GTY variable alloc_object_size_limit looks suspicious,
>>> maybe tree objects returned by alloc_max_size after the change are out
>>> of GC's tracking?
>>>
>>> If the suspicion holds, the attached explorative diff may help.
>>
>> I wouldn't expect that to make a difference.  There are thousands
>> of similar calls to build_int_cst() throughout the middle end.
>>
>> Looking at the original patch, the change that I'm not sure about
>> and that shouldn't have been part of the refactoring is the call
>> to enable_ranger() in pass_waccess::execute().  It's something
>> I was planning to do next.  But even that I wouldn't expect to
>> eat up a whole 1GB or memory.
> 
> I have reproduced the excessive memory consumption with
> the rlwimi-0.c test and a powerpc-linux cross-compiler, and
> confirmed that it is indeed caused by the call to enable_ranger().
> The test defines some six thousand functions so it seems that
> unless each call enable_ranger() is paired with some call to
> release the memory it allocates the memory leaks.
> 
> The removal of the alloc_object_size_limit global variable doesn't
> have any effect on the test case.  The function that used it (and
> now calls build_int_cst () instead) isn't called when the test
> is compiled  (It's only called for calls to allocation functions
> in the source and the test case has none.
> 

Thanks for the clarification and sorry for noisy suspicion!

BR,
Kewen

> Let me take care of releasing the ranger memory.
> 
> Martin
> 
> 
>>
>>>
>>> BR,
>>> Kewen
>>>
>>>> Previously, compiler bootstrap and all testcases ran with a data size
>>>> of 1GB.  After your change, the data size required for those
>>>> particular testcases jumped to 2GB.
>>>>
>>>> The testcases are
>>>>
>>>> gcc/testsuite/gcc.target/powerpc/rlwimi-[012].c
>>>>
>>>> The failure is
>>>>
>>>> cc1: out of memory allocating 65536 bytes after a total of 1608979296
>>>>
>>>> This seems like a significant memory use regression.  Any ideas what happened?
>>
>> Not really.  The patch just moved code around.  I didn't make any
>> changes that I'd expect to impact memory allocation to an appreciable
>> extent, at least not intentionally.  Let me look into it and get back
>> to you.
>>
>> Martin
>>
>>>>
>>>> Thanks, David
>>>>
>>
> 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] more warning code refactoring
  2021-08-19 18:53       ` Martin Sebor
@ 2021-08-19 19:51         ` Segher Boessenkool
  0 siblings, 0 replies; 14+ messages in thread
From: Segher Boessenkool @ 2021-08-19 19:51 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Kewen.Lin, David Edelsohn, GCC Patches

On Thu, Aug 19, 2021 at 12:53:16PM -0600, Martin Sebor wrote:
> That said, I introduced
> the variable in r243470 to begin with and I consider its removal
> a trivially correct and appropriate part of refactoring.

It is not a refactoring.  It changes behaviour.


Segher

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] more warning code refactoring
  2021-08-19 15:36     ` Segher Boessenkool
@ 2021-08-19 18:53       ` Martin Sebor
  2021-08-19 19:51         ` Segher Boessenkool
  0 siblings, 1 reply; 14+ messages in thread
From: Martin Sebor @ 2021-08-19 18:53 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: Kewen.Lin, David Edelsohn, GCC Patches

On 8/19/21 9:36 AM, Segher Boessenkool wrote:
> On Thu, Aug 19, 2021 at 09:03:44AM -0600, Martin Sebor via Gcc-patches wrote:
>> On 8/18/21 11:56 PM, Kewen.Lin wrote:
>>> To get rid of GTY variable alloc_object_size_limit looks suspicious,
>>> maybe tree objects returned by alloc_max_size after the change are out
>>> of GC's tracking?
>>
>> I wouldn't expect that to make a difference.  There are thousands
>> of similar calls to build_int_cst() throughout the middle end.
> 
> But it does make a huge difference.  It has nothing to do with the calls
> to build_int_cst, either.
> 
> Please don't mess with GTY (and call it a refactoring, to add insult to
> injury) if you do not know what you are doing :-(

As I explained, the leak was caused by failing to pair the call to
enable_ranger() with the corresponding call to disable_ranger().
The removal of the global GTY variable has no impact on the test
case, or on memory usage in general.  That said, I introduced
the variable in r243470 to begin with and I consider its removal
a trivially correct and appropriate part of refactoring.

> 
>> Looking at the original patch, the change that I'm not sure about
>> and that shouldn't have been part of the refactoring is the call
>> to enable_ranger() in pass_waccess::execute().  It's something
>> I was planning to do next.  But even that I wouldn't expect to
>> eat up a whole 1GB or memory.
> 
> The testcase is super heavy in the instruction combiner, so you get a
> lot of garbage.  Which is not a problem, except you made the garbage
> collector not pick this up, so we get a ton of garbage accumulating.

Neither that nor anything else you said is relevant or helpful.
On the off chance were trying to be and not just using this as
an opportunity to lecture, I recommend you do your homework
first next time and choose your words more carefully.

Martin

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] more warning code refactoring
  2021-08-19 15:03   ` Martin Sebor
  2021-08-19 15:36     ` Segher Boessenkool
@ 2021-08-19 16:30     ` Martin Sebor
  2021-08-20  1:38       ` Kewen.Lin
  1 sibling, 1 reply; 14+ messages in thread
From: Martin Sebor @ 2021-08-19 16:30 UTC (permalink / raw)
  To: Kewen.Lin, David Edelsohn; +Cc: GCC Patches

On 8/19/21 9:03 AM, Martin Sebor wrote:
> On 8/18/21 11:56 PM, Kewen.Lin wrote:
>> Hi David,
>>
>> on 2021/8/19 上午11:26, David Edelsohn via Gcc-patches wrote:
>>> Hi, Martin
>>>
>>> A few PowerPC-specific testcases started failing yesterday on AIX with
>>> a strange failure mode: the compiler runs out of memory.  As you may
>>> expect from telling you this in an email reply to your patch, I have
>>> bisected the failure and landed on your commit.  I can alternate
>>> between the previous commit and your commit, and the failure
>>> definitely appears with your patch, although I'm unsure how your patch
>>> affected memory allocation in the compiler.  Maybe moving the code
>>> changed a type of allocation or some memory no longer is being freed?
>>>
>>
>>
>> To get rid of GTY variable alloc_object_size_limit looks suspicious,
>> maybe tree objects returned by alloc_max_size after the change are out
>> of GC's tracking?
>>
>> If the suspicion holds, the attached explorative diff may help.
> 
> I wouldn't expect that to make a difference.  There are thousands
> of similar calls to build_int_cst() throughout the middle end.
> 
> Looking at the original patch, the change that I'm not sure about
> and that shouldn't have been part of the refactoring is the call
> to enable_ranger() in pass_waccess::execute().  It's something
> I was planning to do next.  But even that I wouldn't expect to
> eat up a whole 1GB or memory.

I have reproduced the excessive memory consumption with
the rlwimi-0.c test and a powerpc-linux cross-compiler, and
confirmed that it is indeed caused by the call to enable_ranger().
The test defines some six thousand functions so it seems that
unless each call enable_ranger() is paired with some call to
release the memory it allocates the memory leaks.

The removal of the alloc_object_size_limit global variable doesn't
have any effect on the test case.  The function that used it (and
now calls build_int_cst () instead) isn't called when the test
is compiled  (It's only called for calls to allocation functions
in the source and the test case has none.

Let me take care of releasing the ranger memory.

Martin


> 
>>
>> BR,
>> Kewen
>>
>>> Previously, compiler bootstrap and all testcases ran with a data size
>>> of 1GB.  After your change, the data size required for those
>>> particular testcases jumped to 2GB.
>>>
>>> The testcases are
>>>
>>> gcc/testsuite/gcc.target/powerpc/rlwimi-[012].c
>>>
>>> The failure is
>>>
>>> cc1: out of memory allocating 65536 bytes after a total of 1608979296
>>>
>>> This seems like a significant memory use regression.  Any ideas what 
>>> happened?
> 
> Not really.  The patch just moved code around.  I didn't make any
> changes that I'd expect to impact memory allocation to an appreciable
> extent, at least not intentionally.  Let me look into it and get back
> to you.
> 
> Martin
> 
>>>
>>> Thanks, David
>>>
> 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] more warning code refactoring
  2021-08-19  5:56 ` Kewen.Lin
  2021-08-19 14:09   ` Segher Boessenkool
  2021-08-19 15:03   ` Martin Sebor
@ 2021-08-19 16:02   ` David Edelsohn
  2 siblings, 0 replies; 14+ messages in thread
From: David Edelsohn @ 2021-08-19 16:02 UTC (permalink / raw)
  To: Kewen.Lin; +Cc: GCC Patches, Martin Sebor

Hi, Kewen

Good catch!

The patch is in the right direction, but gimple-ssa-warn-access.cc is
the first file that requires GTY and ends in ".cc".  The GCC Makefile
machinery to create the GTY headers performs the substitution for
files with file extension ".c", so this requires more adjustment in
the Makefile.

Thanks, David

On Thu, Aug 19, 2021 at 1:57 AM Kewen.Lin <linkw@linux.ibm.com> wrote:
>
> Hi David,
>
> on 2021/8/19 上午11:26, David Edelsohn via Gcc-patches wrote:
> > Hi, Martin
> >
> > A few PowerPC-specific testcases started failing yesterday on AIX with
> > a strange failure mode: the compiler runs out of memory.  As you may
> > expect from telling you this in an email reply to your patch, I have
> > bisected the failure and landed on your commit.  I can alternate
> > between the previous commit and your commit, and the failure
> > definitely appears with your patch, although I'm unsure how your patch
> > affected memory allocation in the compiler.  Maybe moving the code
> > changed a type of allocation or some memory no longer is being freed?
> >
>
>
> To get rid of GTY variable alloc_object_size_limit looks suspicious,
> maybe tree objects returned by alloc_max_size after the change are out
> of GC's tracking?
>
> If the suspicion holds, the attached explorative diff may help.
>
> BR,
> Kewen
>
> > Previously, compiler bootstrap and all testcases ran with a data size
> > of 1GB.  After your change, the data size required for those
> > particular testcases jumped to 2GB.
> >
> > The testcases are
> >
> > gcc/testsuite/gcc.target/powerpc/rlwimi-[012].c
> >
> > The failure is
> >
> > cc1: out of memory allocating 65536 bytes after a total of 1608979296
> >
> > This seems like a significant memory use regression.  Any ideas what happened?
> >
> > Thanks, David
> >

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] more warning code refactoring
  2021-08-19 15:03   ` Martin Sebor
@ 2021-08-19 15:36     ` Segher Boessenkool
  2021-08-19 18:53       ` Martin Sebor
  2021-08-19 16:30     ` Martin Sebor
  1 sibling, 1 reply; 14+ messages in thread
From: Segher Boessenkool @ 2021-08-19 15:36 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Kewen.Lin, David Edelsohn, GCC Patches

On Thu, Aug 19, 2021 at 09:03:44AM -0600, Martin Sebor via Gcc-patches wrote:
> On 8/18/21 11:56 PM, Kewen.Lin wrote:
> >To get rid of GTY variable alloc_object_size_limit looks suspicious,
> >maybe tree objects returned by alloc_max_size after the change are out
> >of GC's tracking?
> 
> I wouldn't expect that to make a difference.  There are thousands
> of similar calls to build_int_cst() throughout the middle end.

But it does make a huge difference.  It has nothing to do with the calls
to build_int_cst, either.

Please don't mess with GTY (and call it a refactoring, to add insult to
injury) if you do not know what you are doing :-(

> Looking at the original patch, the change that I'm not sure about
> and that shouldn't have been part of the refactoring is the call
> to enable_ranger() in pass_waccess::execute().  It's something
> I was planning to do next.  But even that I wouldn't expect to
> eat up a whole 1GB or memory.

The testcase is super heavy in the instruction combiner, so you get a
lot of garbage.  Which is not a problem, except you made the garbage
collector not pick this up, so we get a ton of garbage accumulating.


Segher

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] more warning code refactoring
  2021-08-19  5:56 ` Kewen.Lin
  2021-08-19 14:09   ` Segher Boessenkool
@ 2021-08-19 15:03   ` Martin Sebor
  2021-08-19 15:36     ` Segher Boessenkool
  2021-08-19 16:30     ` Martin Sebor
  2021-08-19 16:02   ` David Edelsohn
  2 siblings, 2 replies; 14+ messages in thread
From: Martin Sebor @ 2021-08-19 15:03 UTC (permalink / raw)
  To: Kewen.Lin, David Edelsohn; +Cc: GCC Patches

On 8/18/21 11:56 PM, Kewen.Lin wrote:
> Hi David,
> 
> on 2021/8/19 上午11:26, David Edelsohn via Gcc-patches wrote:
>> Hi, Martin
>>
>> A few PowerPC-specific testcases started failing yesterday on AIX with
>> a strange failure mode: the compiler runs out of memory.  As you may
>> expect from telling you this in an email reply to your patch, I have
>> bisected the failure and landed on your commit.  I can alternate
>> between the previous commit and your commit, and the failure
>> definitely appears with your patch, although I'm unsure how your patch
>> affected memory allocation in the compiler.  Maybe moving the code
>> changed a type of allocation or some memory no longer is being freed?
>>
> 
> 
> To get rid of GTY variable alloc_object_size_limit looks suspicious,
> maybe tree objects returned by alloc_max_size after the change are out
> of GC's tracking?
> 
> If the suspicion holds, the attached explorative diff may help.

I wouldn't expect that to make a difference.  There are thousands
of similar calls to build_int_cst() throughout the middle end.

Looking at the original patch, the change that I'm not sure about
and that shouldn't have been part of the refactoring is the call
to enable_ranger() in pass_waccess::execute().  It's something
I was planning to do next.  But even that I wouldn't expect to
eat up a whole 1GB or memory.

> 
> BR,
> Kewen
> 
>> Previously, compiler bootstrap and all testcases ran with a data size
>> of 1GB.  After your change, the data size required for those
>> particular testcases jumped to 2GB.
>>
>> The testcases are
>>
>> gcc/testsuite/gcc.target/powerpc/rlwimi-[012].c
>>
>> The failure is
>>
>> cc1: out of memory allocating 65536 bytes after a total of 1608979296
>>
>> This seems like a significant memory use regression.  Any ideas what happened?

Not really.  The patch just moved code around.  I didn't make any
changes that I'd expect to impact memory allocation to an appreciable
extent, at least not intentionally.  Let me look into it and get back
to you.

Martin

>>
>> Thanks, David
>>


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] more warning code refactoring
  2021-08-19  5:56 ` Kewen.Lin
@ 2021-08-19 14:09   ` Segher Boessenkool
  2021-08-19 15:03   ` Martin Sebor
  2021-08-19 16:02   ` David Edelsohn
  2 siblings, 0 replies; 14+ messages in thread
From: Segher Boessenkool @ 2021-08-19 14:09 UTC (permalink / raw)
  To: Kewen.Lin; +Cc: David Edelsohn, GCC Patches

Hi!

On Thu, Aug 19, 2021 at 01:56:56PM +0800, Kewen.Lin via Gcc-patches wrote:
> on 2021/8/19 上午11:26, David Edelsohn via Gcc-patches wrote:
> > A few PowerPC-specific testcases started failing yesterday on AIX with
> > a strange failure mode: the compiler runs out of memory.  As you may
> > expect from telling you this in an email reply to your patch, I have
> > bisected the failure and landed on your commit.  I can alternate
> > between the previous commit and your commit, and the failure
> > definitely appears with your patch, although I'm unsure how your patch
> > affected memory allocation in the compiler.  Maybe moving the code
> > changed a type of allocation or some memory no longer is being freed?
> 
> To get rid of GTY variable alloc_object_size_limit looks suspicious,
> maybe tree objects returned by alloc_max_size after the change are out
> of GC's tracking?

That looks exactly right.  Thanks Ke Wen!

This also means this was not a refactoring at all -- nothing changing
anything to do with GC is ever a refactoring.  Refactorings are trivial
one-to-one code transforms that do not change semantics at all.


Segher

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] more warning code refactoring
  2021-08-19  3:26 David Edelsohn
@ 2021-08-19  5:56 ` Kewen.Lin
  2021-08-19 14:09   ` Segher Boessenkool
                     ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Kewen.Lin @ 2021-08-19  5:56 UTC (permalink / raw)
  To: David Edelsohn; +Cc: GCC Patches, Martin Sebor

[-- Attachment #1: Type: text/plain, Size: 1340 bytes --]

Hi David,

on 2021/8/19 上午11:26, David Edelsohn via Gcc-patches wrote:
> Hi, Martin
> 
> A few PowerPC-specific testcases started failing yesterday on AIX with
> a strange failure mode: the compiler runs out of memory.  As you may
> expect from telling you this in an email reply to your patch, I have
> bisected the failure and landed on your commit.  I can alternate
> between the previous commit and your commit, and the failure
> definitely appears with your patch, although I'm unsure how your patch
> affected memory allocation in the compiler.  Maybe moving the code
> changed a type of allocation or some memory no longer is being freed?
> 


To get rid of GTY variable alloc_object_size_limit looks suspicious,
maybe tree objects returned by alloc_max_size after the change are out
of GC's tracking?

If the suspicion holds, the attached explorative diff may help.

BR,
Kewen

> Previously, compiler bootstrap and all testcases ran with a data size
> of 1GB.  After your change, the data size required for those
> particular testcases jumped to 2GB.
> 
> The testcases are
> 
> gcc/testsuite/gcc.target/powerpc/rlwimi-[012].c
> 
> The failure is
> 
> cc1: out of memory allocating 65536 bytes after a total of 1608979296
> 
> This seems like a significant memory use regression.  Any ideas what happened?
> 
> Thanks, David
> 

[-- Attachment #2: alloc_object_size_limit.diff --]
[-- Type: text/plain, Size: 1755 bytes --]

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 6653e9e2142..9aefed47be8 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -2717,7 +2717,7 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/sancov.c \
   $(srcdir)/ipa-devirt.c \
   $(srcdir)/internal-fn.h \
-  $(srcdir)/calls.c \
+  $(srcdir)/gimple-ssa-warn-access.cc \
   $(srcdir)/omp-general.h \
   @all_gtfiles@
 
diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index f3efe564af0..267ef987edd 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -2301,6 +2301,9 @@ pass_waccess::gate (function *)
 	  || warn_mismatched_new_delete);
 }
 
+/* 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.  */
@@ -2308,11 +2311,16 @@ pass_waccess::gate (function *)
 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));
 
-  return build_int_cst (size_type_node, limit);
+  alloc_object_size_limit = build_int_cst (size_type_node, limit);
+
+  return alloc_object_size_limit;
 }
 
 /* Diagnose a call EXP to function FN decorated with attribute alloc_size
@@ -3328,3 +3336,6 @@ make_pass_warn_access (gcc::context *ctxt)
 {
   return new pass_waccess (ctxt);
 }
+
+/* Tell the garbage collector about GTY markers in this source file.  */
+#include "gt-gimple-ssa-warn-access.h"

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] more warning code refactoring
@ 2021-08-19  3:26 David Edelsohn
  2021-08-19  5:56 ` Kewen.Lin
  0 siblings, 1 reply; 14+ messages in thread
From: David Edelsohn @ 2021-08-19  3:26 UTC (permalink / raw)
  To: Martin Sebor; +Cc: GCC Patches

Hi, Martin

A few PowerPC-specific testcases started failing yesterday on AIX with
a strange failure mode: the compiler runs out of memory.  As you may
expect from telling you this in an email reply to your patch, I have
bisected the failure and landed on your commit.  I can alternate
between the previous commit and your commit, and the failure
definitely appears with your patch, although I'm unsure how your patch
affected memory allocation in the compiler.  Maybe moving the code
changed a type of allocation or some memory no longer is being freed?

Previously, compiler bootstrap and all testcases ran with a data size
of 1GB.  After your change, the data size required for those
particular testcases jumped to 2GB.

The testcases are

gcc/testsuite/gcc.target/powerpc/rlwimi-[012].c

The failure is

cc1: out of memory allocating 65536 bytes after a total of 1608979296

This seems like a significant memory use regression.  Any ideas what happened?

Thanks, David

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2021-08-20 14:49 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-17  1:51 [PATCH] more warning code refactoring Martin Sebor
2021-08-17  8:51 ` Richard Biener
2021-08-17 21:09   ` Martin Sebor
2021-08-19  3:26 David Edelsohn
2021-08-19  5:56 ` Kewen.Lin
2021-08-19 14:09   ` Segher Boessenkool
2021-08-19 15:03   ` Martin Sebor
2021-08-19 15:36     ` Segher Boessenkool
2021-08-19 18:53       ` Martin Sebor
2021-08-19 19:51         ` Segher Boessenkool
2021-08-19 16:30     ` Martin Sebor
2021-08-20  1:38       ` Kewen.Lin
2021-08-20 14:49         ` Martin Sebor
2021-08-19 16:02   ` David Edelsohn

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).