public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* RFA: new pass to warn on questionable uses of alloca() and VLAs
@ 2016-07-08 11:48 Aldy Hernandez
  2016-07-10 22:09 ` Martin Sebor
                   ` (2 more replies)
  0 siblings, 3 replies; 26+ messages in thread
From: Aldy Hernandez @ 2016-07-08 11:48 UTC (permalink / raw)
  To: gcc-patches, Martin Sebor, Jeff Law; +Cc: gcc-patches, Andrew MacLeod

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

[New thread now that I actually have a tested patch :)].

> I think detecting potentially problematic uses of alloca would
> be useful, especially when done in an intelligent way like in
> your patch (as opposed to simply diagnosing every call to
> the function regardless of the value of its argument).  At
> the same time, it seems that an even more reliable solution
> than pointing out potentially unsafe calls to the function
> and relying on users to modify their code to use malloc for
> large/unbounded allocations would be to let GCC do it for
> them automatically (i.e., in response to some other option,
> emit a call to malloc instead, and insert a call to free when
> appropriate).

As Jeff said, we were thinking the other way around: notice a malloced 
area that doesn't escape and replace it with a call to alloca.  But all 
this is beyond the scope of this patch.

>
> I applied the patch and experimented with it a bit (I haven't
> studied the code in any detail yet) and found a few opportunities
> for improvements.  I describe them below (Sorry in advance for
> the length of my comments!)

BTW, thank you so much for taking the time to look into this.  Your 
feedback has been invaluable.

>
> I found the "warning: unbounded use of alloca" misleading when
> a call to the function was, in fact, bounded but to a limit
> that's greater than alloca-max-size as in the program below:

I have added various levels of granularity for the warning, along with 
appropriately different messages:

// Possible problematic uses of alloca.
enum alloca_type {
   // Alloca argument is within known bounds that are appropriate.
   ALLOCA_OK,

   // Alloca argument is KNOWN to have a value that is too large.
   ALLOCA_BOUND_DEFINITELY_LARGE,

   // Alloca argument may be too large.
   ALLOCA_BOUND_MAYBE_LARGE,

   // Alloca argument is bounded but of an indeterminate size.
   ALLOCA_BOUND_UNKNOWN,

   // Alloca argument was casted from a signed integer.
   ALLOCA_CAST_FROM_SIGNED,

   // Alloca appears in a loop.
   ALLOCA_IN_LOOP,

   // Alloca call is unbounded.  That is, there is no controlling
   // predicate for its argument.
   ALLOCA_UNBOUNDED
};

Of course, there are plenty of cases where we can't get the exact 
diagnosis (due to the limitations on our range info) and we fall back to 
ALLOCA_UNBOUNDED or ALLOCA_BOUND_MAYBE_LARGE.  In practice, I'm 
wondering whether we should lump everything into 2-3 warnings instead of 
trying so hard to get the exact reason for the problematic use of 
alloca.  (More details on upcoming changes to range info further down.)

>
>   void f (void*);
>
>   void g (int n)
>   {
>     void *p;
>     if (n < 4096)
>       p = __builtin_alloca (n);
>     else
>       p = __builtin_malloc (n);
>     f (p);
>   }
>   t.C: In function ‘g’:
>   t.C:7:7: warning: unbounded use of alloca [-Walloca]
>        p = __builtin_alloca (n);

Well, in this particular case you are using a signed int, so n < 4096 
can cause the value passed to alloca  to be rather large in the case of 
n < 0.

>
> I would suggest to rephrase the diagnostic to mention the limit,
> e.g.,
>
>   warning: calling alloca with an argument in excess of '4000'
>   bytes

In the attached patch I try to diagnose these cases with:

a.c: In function ‘g’:
a.c:7:10: warning: cast from signed type in alloca [-Walloca]
p = __builtin_alloca (n);

I'm not 100% convinced this the best idea, and I could be easily 
convinced to narrow the wide variety of warning cases I currently have 
into just a handful less specific ones.

>
> I'm not sure I understand how -Walloca-max-size is supposed to
> be used.  For example, it has no effect on the test case above
> (i.e., I couldn't find a way to use it to raise the limit to
> avoid the warning).  Maybe the interaction of the two options
> is more subtle than I think.  I would have expected either

If by subtle you mean buggy, then yes-- thank you for your kind words 
:).  I have fixed it all, and those found responsible have been sacked.

> a single option to control whether alloca warnings are to be
> emitted and also (optionally) the allocation threshold, or
> perhaps two options, one to turn the warning on and off, and
> another just to override the threshold (though this latter
> approach seems superfluous given that a single option can do
> both).
...
> I also think that VLA diagnostics would be better controlled
> by a separate option, and emit a different diagnostic (one

I have overhauled the options and added extensive documentation to 
invoke.texi explaining them.  See the included testcases.  I have tried 
to add a testcase for everything the pass currently handles.

In the interest of keeping a consistent relationship with -Wvla, we now 
have:

-Walloca:	Warn on every use of alloca (not VLAs).
-Walloca=999:	Warn on unbounded uses of alloca, bounded uses with
		no known limit, and bounded uses where the number of
		bytes is greater than 999.
-Wvla:		Behaves as currently (warn on every use of VLAs).
-Wvla=999:	Similar to -Walloca=999, but for -Wvla.

Notice plain -Walloca doesn't have a default, and just warns on every 
use of alloca, just like -Wvla does for VLAs.  This way we can be 
consistent with -Wvla, and just add the -Wvla=999 variant.

I have added appropriate warnings to avoid confusion with -Wvla=0 and 
-Walloca=0, because they would conflict with -Wno-vla and -Wno-alloca 
(setting warn_vla=0 and warn_alloca=0 respectively).

The option handling is a bit convoluted because no -Wvla passed is 
warn_vla == -1, and CPP and the FE's depend on this information to know 
when no -Wvla was passed (pedantic warnings and some CPP pre-defines). 
So to keep everything consistent I had to differentiate between no -Wvla 
passed, plain -Wvla passed, and -Wvla=999 passed, without getting 
confused by -Wvla=0 and -Wno-vla.  Ughhh...

> Beyond a separate option for VLAs, in my limited testing I
> couldn't figure out how constrain the VLA size so that using
> -Walloca wouldn't complain for example on the following code:
>
>   void f (void*);
>
>   void h (int n)
>   {
>     if (n < 100)
>     {
>       int a [n];
>       f (a);
>     }
>   }

Fixed.  Also, you have a signed int here as well.  That could cause a 
very large allocation.

This patch depends on range information, which is less than stellar past 
the VRP pass.  To get better range information, we'd have to incorporate 
this somehow into the VRP pass and use the ASSERT_EXPRs therein.  And 
still, VRP gets awfully confused with PHI merge points.  Andrew Macleod 
is working on a new fancy range info infrastructure that should 
eliminate a lot of the false positives we may get and/or help us 
diagnose a wider range of cases.  Hence the reason that I'm not bending 
over backwards to incorporate this pass into tree-vrp.c.

FYI, I have a few XFAILed tests in this patch, to make sure we don't 
lose track of possible improvements (which in this case should be 
handled by better range info).  What's the blessed way of doing this? 
Are adding new XFAILed tests acceptable?

I have regstrapped this patch on x86-64 Linux, and have tested the 
resulting compiler by building glibc with:

/source/glibc/configure --prefix=/usr CC="/path/bin/gcc -Walloca=5000" 
--disable-werror

This of course, pointed out all sorts of interesting things!

Fire away!

Aldy

[-- Attachment #2: curr --]
[-- Type: text/plain, Size: 34476 bytes --]

gcc/

	* Makefile.in (OBJS): Add gimple-ssa-warn-walloca.o.
	* common.opt (Walloca): New.
	(Walloca=): New.
	* passes.def: Add pass_walloca.
	* tree-pass.h (make_pass_walloca): New.
	* gimple-ssa-warn-walloca.c: New file.
	* opts.c (finish_options): Warn on specific variants of -Walloca
	and -Wvla=.
	(common_handle_option): Add cases for OPT_Walloca and OPT_Walloca_.
	* doc/invoke.texi: Document -Walloca, -Walloca=, and -Wvla
	options.

gcc/c-family/

	* c-cppbuiltin.c (c_cpp_builtins): Make sure not all negative
	numbers get treated the same when evaluating warn_vla.
	* c-opts.c (c_common_handle_option): Add case for OPT_Wvla and
	OPT_Wvla_.
	* c.opt: Add entries for Walloca, Walloca=, and Wvla=.

gcc/c/

	* c-decl.c (warn_variable_length_array): Do not warn when
	-Wvla=999 is being used.
	* c-errors.c (pedwarn_c90): Not all negative numbers case a
	warning to be silenced.

gcc/cp/

	* decl.c (compute_array_index_type): Handle -Wvla=999 warning.

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 776f6d7..2a13b8f 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1284,6 +1284,7 @@ OBJS = \
 	gimple-ssa-nonnull-compare.o \
 	gimple-ssa-split-paths.o \
 	gimple-ssa-strength-reduction.o \
+	gimple-ssa-warn-alloca.o \
 	gimple-streamer-in.o \
 	gimple-streamer-out.o \
 	gimple-walk.o \
diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
index 408ad47..3cf13d9 100644
--- a/gcc/c-family/c-cppbuiltin.c
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -827,7 +827,7 @@ c_cpp_builtins (cpp_reader *pfile)
 	 (corresponding to the initial test release of GNU C++) if we won't
 	 complain about use of VLAs.  */
       if (c_dialect_cxx ()
-	  && (pedantic ? warn_vla == 0 : warn_vla <= 0))
+	  && (pedantic ? warn_vla == 0 : warn_vla == -1))
 	cpp_define (pfile, "__cpp_runtime_arrays=198712");
 
       if (cxx_dialect >= cxx11)
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index ff6339c..71dd170 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -376,6 +376,19 @@ c_common_handle_option (size_t scode, const char *arg, int value,
       cpp_opts->warn_num_sign_change = value;
       break;
 
+    case OPT_Wvla:
+      /* Plain -Wvla will set warn_vla to 1, but this conflicts with
+	 -Wvla=1.  Set to -2 here which means -Wvla was set with no
+	 argument.  */
+      if (value == 1)
+	warn_vla = -2;
+      break;
+
+    case OPT_Wvla_:
+      if (value == 0)
+	inform (loc, "-Wvla=0 disables -Wvla.  Use -Wno-vla instead.");
+      break;
+
     case OPT_Wunknown_pragmas:
       /* Set to greater than 1, so that even unknown pragmas in
 	 system headers will be warned about.  */
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 83fd84c..5221e0c 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -275,6 +275,14 @@ Wall
 C ObjC C++ ObjC++ Warning
 Enable most warning messages.
 
+Walloca
+LangEnabledBy(C ObjC C++ ObjC++)
+; in common.opt
+
+Walloca=
+LangEnabledBy(C ObjC C++ ObjC++)
+; in common.opt
+
 Warray-bounds
 LangEnabledBy(C ObjC C++ ObjC++,Wall)
 ; in common.opt
@@ -976,10 +984,20 @@ Wvarargs
 C ObjC C++ ObjC++ Warning Var(warn_varargs) Init(1)
 Warn about questionable usage of the macros used to retrieve variable arguments.
 
+;; warn_vla == 0 for -Wno-vla
+;; warn_vla == -1 for nothing passed.
+;; warn_vla == -2 for -Wvla passed
+;; warn_vla == NUM for -Wvla=NUM
 Wvla
 C ObjC C++ ObjC++ Var(warn_vla) Init(-1) Warning
 Warn if a variable length array is used.
 
+Wvla=
+C ObjC C++ ObjC++ Var(warn_vla) Warning Joined RejectNegative UInteger
+-Wvla=<number> Warn on unbounded uses of variable-length arrays, and
+warn on bounded uses of variable-length arrays whose bound can be
+larger than <number> bytes.
+
 Wvolatile-register-var
 C ObjC C++ ObjC++ Var(warn_volatile_register_var) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
 Warn when a register variable is declared volatile.
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 5c08c59..0a34d23 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -5247,6 +5247,11 @@ check_bitfield_type_and_width (location_t loc, tree *type, tree *width,
 static void
 warn_variable_length_array (tree name, tree size)
 {
+  /* warn_vla > 0 is -Wvla=9999 which warns on specific instances of
+     VLA, not generically on all.  */
+  if (warn_vla > 0)
+    return;
+
   if (TREE_CONSTANT (size))
     {
       if (name)
diff --git a/gcc/c/c-errors.c b/gcc/c/c-errors.c
index af157c0..d7d4d9e 100644
--- a/gcc/c/c-errors.c
+++ b/gcc/c/c-errors.c
@@ -86,7 +86,7 @@ pedwarn_c90 (location_t location, int opt, const char *gmsgid, ...)
       int opt_var = *(int *) option_flag_var (opt, &global_options);
       if (opt_var == 0)
         goto out;
-      else if (opt_var > 0)
+      else if (opt_var != -1)
 	{
 	  diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
 			       (pedantic && !flag_isoc99)
diff --git a/gcc/common.opt b/gcc/common.opt
index f0d7196..7edcdc6 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -545,6 +545,19 @@ Waggressive-loop-optimizations
 Common Var(warn_aggressive_loop_optimizations) Init(1) Warning
 Warn if a loop with constant number of iterations triggers undefined behavior.
 
+;; warn_alloca == 0 for -Wno-alloca
+;; warn_alloca == -1 for nothing passed.
+;; warn_alloca == -2 for -Walloca passed
+;; warn_alloca == NUM for -Walloca=NUM
+Walloca
+Common Var(warn_alloca) Warning Init(-1)
+Warn on all uses of alloca.
+
+Walloca=
+Common Joined RejectNegative UInteger Var(warn_alloca) Warning
+-Walloca=<number>	Warn on unbounded uses of alloca, and warn on
+bounded uses of alloca whose argument can be larger than <number> bytes.
+
 Warray-bounds
 Common Var(warn_array_bounds) Warning
 Warn if an array is accessed out of bounds.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index a03e48f..b8a2489 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8870,14 +8870,19 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
 	error ("size of array is not an integral constant-expression");
       size = integer_one_node;
     }
-  else if (pedantic && warn_vla != 0)
+  /* In pedantic mode, warn if no -Wvla was explicitly passed
+     (warn_vla == -1) or if -Wvla was passed (warn_vla == -2).  Don't
+     warn on pedantic and -Wvla=xxx, which means something else.  */
+  else if (pedantic && warn_vla < 0)
     {
       if (name)
 	pedwarn (input_location, OPT_Wvla, "ISO C++ forbids variable length array %qD", name);
       else
 	pedwarn (input_location, OPT_Wvla, "ISO C++ forbids variable length array");
     }
-  else if (warn_vla > 0)
+  /* Warn if -Wvla was passed (warn_vla == -2), but not with -Wvla=xxx
+     which means something else.  */
+  else if (warn_vla == -2)
     {
       if (name)
 	warning (OPT_Wvla, 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 2105351..aee1212 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -253,6 +253,7 @@ Objective-C and Objective-C++ Dialects}.
 @gccoptlist{-fsyntax-only  -fmax-errors=@var{n}  -Wpedantic @gol
 -pedantic-errors @gol
 -w  -Wextra  -Wall  -Waddress  -Waggregate-return  @gol
+-Walloca -Walloca=@var{n} @gol
 -Wno-aggressive-loop-optimizations -Warray-bounds -Warray-bounds=@var{n} @gol
 -Wno-attributes -Wbool-compare -Wno-builtin-macro-redefined @gol
 -Wc90-c99-compat -Wc99-c11-compat @gol
@@ -309,7 +310,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wunused-const-variable -Wunused-const-variable=@var{n} @gol
 -Wunused-but-set-parameter -Wunused-but-set-variable @gol
 -Wuseless-cast -Wvariadic-macros -Wvector-operation-performance @gol
--Wvla -Wvolatile-register-var  -Wwrite-strings @gol
+-Wvla -Wvla=@var{n} -Wvolatile-register-var  -Wwrite-strings @gol
 -Wzero-as-null-pointer-constant -Whsa}
 
 @item C and Objective-C-only Warning Options
@@ -4618,6 +4619,56 @@ annotations.
 Warn about overriding virtual functions that are not marked with the override
 keyword.
 
+@item -Walloca
+@itemx -Walloca=@var{n}
+@opindex Wno-alloca
+@opindex Walloca
+This option warns on suspicious uses of @code{alloca}.  If no argument
+is specified, a warning is issued for any use of @code{alloca} in the
+source.  However, if an argument is specified, a warning is issued for
+either unbounded uses of @code{alloca}, or bounded uses of
+@code{alloca} where the argument can be larger than @var{n} bytes.
+
+For example, a bounded case of @code{alloca} could be:
+
+@smallexample
+unsigned int n;
+...
+if (n <= 1000)
+  alloca (n);
+@end smallexample
+
+In the above example, passing @code{-Walloca=500} would cause the
+compiler to warn because the bound can be determined at compile time
+to be larger than 500.
+
+Unbounded uses, on the other hand, are uses of @code{alloca} with no
+controlling predicate verifying its size.  For example:
+
+@smallexample
+stuff ();
+alloca (n);
+@end smallexample
+
+If @code{-Walloca=500} was passed, the above code would also trigger a
+warning, but this time because of the lack of bounds checking.
+
+Note, that even seemingly correct code involving signed integers could
+cause a warning:
+
+@smallexample
+signed int n;
+...
+if (n < 500)
+  alloca (n);
+@end smallexample
+
+In the above example, @var{n} could be negative, causing a larger than
+expected argument to be implicitly casted into the @code{alloca} call.
+
+This warning is not enabled by @option{-Wall}, and is only active when
+@option{-ftree-vrp} is active (default for @option{-O2} and above).
+
 @item -Warray-bounds
 @itemx -Warray-bounds=@var{n}
 @opindex Wno-array-bounds
@@ -5780,11 +5831,20 @@ moved-from state.  If the move assignment operator is written to avoid
 moving from a moved-from object, this warning can be disabled.
 
 @item -Wvla
+@itemx -Wvla=@var{n}
 @opindex Wvla
 @opindex Wno-vla
-Warn if variable length array is used in the code.
+Warn if a variable-length array is used in the code.
 @option{-Wno-vla} prevents the @option{-Wpedantic} warning of
-the variable length array.
+the variable-length array.
+
+If an argument is used with this option, the compiler will only warn
+on uses of variable-length arrays where the size is either unbounded,
+or bounded by an argument that can be larger than @var{n} bytes.  This
+is similar to how @option{-Walloca=@var{n}} works, but with
+variable-length arrays.
+
+See also @option{-Walloca=@var{n}}.
 
 @item -Wvolatile-register-var
 @opindex Wvolatile-register-var
diff --git a/gcc/gimple-ssa-warn-alloca.c b/gcc/gimple-ssa-warn-alloca.c
new file mode 100644
index 0000000..6180d9e
--- /dev/null
+++ b/gcc/gimple-ssa-warn-alloca.c
@@ -0,0 +1,456 @@
+/* Warn on problematic uses of alloca and variable length arrays.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Contributed by Aldy Hernandez <aldyh@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+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/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "ssa.h"
+#include "gimple-pretty-print.h"
+#include "diagnostic-core.h"
+#include "fold-const.h"
+#include "gimple-iterator.h"
+#include "tree-ssa.h"
+#include "params.h"
+#include "tree-cfg.h"
+#include "calls.h"
+#include "cfgloop.h"
+
+const pass_data pass_data_walloca = {
+  GIMPLE_PASS,
+  "walloca",
+  OPTGROUP_NONE,
+  TV_NONE,
+  PROP_cfg, // properties_required
+  0,	    // properties_provided
+  0,	    // properties_destroyed
+  0,	    // properties_start
+  0,	    // properties_finish
+};
+
+class pass_walloca : public gimple_opt_pass
+{
+public:
+  pass_walloca (gcc::context *ctxt)
+    : gimple_opt_pass(pass_data_walloca, ctxt)
+  {}
+  virtual bool gate (function *);
+  virtual unsigned int execute (function *);
+};
+
+bool
+pass_walloca::gate (function *fun ATTRIBUTE_UNUSED)
+{
+  // As a reference:
+  //
+  // nothing passed:	warn_vla = -1
+  // -Wvla:		warn_vla = -2
+  // -Wvla=ARG:		warn_vla = ARG
+  // -Wno-vla:		warn_vla = 0
+  //
+  // nothing passed:	warn_alloca = -1
+  // -Walloca:		warn_alloca = -2
+  // -Walloca=ARG	warn_alloca = ARG
+  // -Wno-alloca:	warn_alloca = 0
+
+  // Normalize those annoying -1 out.
+  if (warn_alloca == -1)
+    warn_alloca = 0;
+  if (warn_vla == -1)
+    warn_vla = 0;
+
+#define alloca_strict_mode	(warn_alloca == -2)
+#define vla_strict_mode		(warn_vla == -2)
+  if (!warn_alloca
+      // -Wvla strict mode is handled in the front-end.
+      && (!warn_vla || vla_strict_mode))
+    return false;
+
+  return true;
+}
+
+// Possible problematic uses of alloca.
+enum alloca_type {
+  // Alloca argument is within known bounds that are appropriate.
+  ALLOCA_OK,
+
+  // Alloca argument is KNOWN to have a value that is too large.
+  ALLOCA_BOUND_DEFINITELY_LARGE,
+
+  // Alloca argument may be too large.
+  ALLOCA_BOUND_MAYBE_LARGE,
+
+  // Alloca argument is bounded but of an indeterminate size.
+  ALLOCA_BOUND_UNKNOWN,
+
+  // Alloca argument was casted from a signed integer.
+  ALLOCA_CAST_FROM_SIGNED,
+
+  // Alloca appears in a loop.
+  ALLOCA_IN_LOOP,
+
+  // Alloca call is unbounded.  That is, there is no controlling
+  // predicate for its argument.
+  ALLOCA_UNBOUNDED
+};
+
+// We have a few heuristics up our sleeve to determine if a call to
+// alloca() is within bounds.  Try them out and return the type of
+// alloca call this is based on its argument.
+//
+// Given a known argument (ARG) to alloca() and an EDGE (E)
+// calculating said argument, verify that the last statement in the BB
+// in E->SRC is a gate comparing ARG to an acceptable bound for
+// alloca().  See examples below.
+//
+// MAX_SIZE is WARN_ALLOCA= adjusted for VLAs.  It is the maximum size
+// in bytes we allow for arg.
+//
+// Returns the alloca type.
+
+static enum alloca_type
+alloca_call_type_by_arg (tree arg, edge e, unsigned max_size)
+{
+  // All the tests bellow depend on the jump being on the TRUE path.
+  if (!(e->flags & EDGE_TRUE_VALUE))
+    return ALLOCA_UNBOUNDED;
+
+  basic_block bb = e->src;
+  gimple_stmt_iterator gsi = gsi_last_bb (bb);
+  gimple *last = gsi_stmt (gsi);
+  if (!last || gimple_code (last) != GIMPLE_COND)
+    return ALLOCA_UNBOUNDED;
+
+  /* Check for:
+     if (ARG <= N)
+       goto <bb 3>;
+      else
+        goto <bb 4>;
+      <bb 3>:
+      alloca(ARG);
+  */
+  if (gimple_cond_code (last) == LE_EXPR
+      && gimple_cond_lhs (last) == arg)
+    {
+      if (TREE_CODE (gimple_cond_rhs (last)) == INTEGER_CST)
+	return
+	  tree_to_uhwi (gimple_cond_rhs (last)) > max_size
+	  ? ALLOCA_BOUND_MAYBE_LARGE : ALLOCA_OK;
+      else
+	return ALLOCA_BOUND_UNKNOWN;
+    }
+
+  /* Check for:
+     if (arg .cond. LIMIT) -or- if (LIMIT .cond. arg)
+       alloca(arg);
+
+     Where LIMIT has a bound of unknown range.  */
+  tree limit = NULL;
+  if (gimple_cond_lhs (last) == arg)
+    limit = gimple_cond_rhs (last);
+  else if (gimple_cond_rhs (last) == arg)
+    limit = gimple_cond_lhs (last);
+  if (limit && TREE_CODE (limit) == SSA_NAME)
+    {
+      wide_int min, max;
+      value_range_type range_type = get_range_info (limit, &min, &max);
+      if (range_type == VR_UNDEFINED || range_type == VR_VARYING)
+	return ALLOCA_BOUND_UNKNOWN;
+      // FIXME: We could try harder here and handle a possible range
+      // or anti-range.  Hopefully the upcoming changes to range info
+      // will give us finer grained info, and we can avoid somersaults
+      // here.
+    }
+
+  return ALLOCA_UNBOUNDED;
+}
+
+// Return TRUE if SSA's definition is a cast from a signed type.
+
+static bool
+cast_from_signed_p (tree ssa)
+{
+  gimple *def = SSA_NAME_DEF_STMT (ssa);
+  if (!def || gimple_nop_p (def))
+    return false;
+  return (gimple_assign_cast_p (def)
+	  && !TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (def))));
+}
+
+// Return TURE if X has a maximum range of MAX, basically covering the
+// entire domain, in which case it's no range at all.
+
+static bool
+is_max (tree x, wide_int max)
+{
+  return wi::max_value (TREE_TYPE (x)) == max;
+}
+
+// Analyze the alloca call in STMT and return an `enum alloca_type'
+// explaining what type of alloca it is.  IS_VLA is set if the alloca
+// call is really a BUILT_IN_ALLOCA_WITH_ALIGN, signifying a VLA.
+
+static enum alloca_type
+alloca_call_type (gimple *stmt, bool is_vla)
+{
+  gcc_assert (gimple_alloca_call_p (stmt));
+  tree len = gimple_call_arg (stmt, 0);
+  enum alloca_type w = ALLOCA_UNBOUNDED;
+  wide_int min, max;
+
+  gcc_assert (warn_vla > 0 || !is_vla);
+  gcc_assert (warn_alloca > 0 || is_vla);
+
+  // Check if we're in a loop.
+  basic_block bb = gimple_bb (stmt);
+  if (bb->loop_father
+      // ?? Functions with no loops get a loop_father?  I
+      // don't get it.  The following conditional seems to do
+      // the trick to exclude such nonsense.
+      && bb->loop_father->header != ENTRY_BLOCK_PTR_FOR_FN (cfun))
+    {
+      // Do not warn on VLAs occurring in a loop, since VLAs are
+      // guaranteed to be cleaned up when they go out of scope.
+      // That is, there is a corresponding __builtin_stack_restore
+      // at the end of the scope in which the VLA occurs.
+      tree fndecl = gimple_call_fn (stmt);
+      while (TREE_CODE (fndecl) == ADDR_EXPR)
+	fndecl = TREE_OPERAND (fndecl, 0);
+      if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+	  && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA_WITH_ALIGN)
+	return ALLOCA_OK;
+
+      return ALLOCA_IN_LOOP;
+    }
+
+  // Adjust warn_alloca_max_size for VLAs, by taking the underlying
+  // type into account.
+  unsigned HOST_WIDE_INT max_size;
+  if (is_vla)
+    max_size = (unsigned HOST_WIDE_INT) warn_vla;
+  else
+    max_size = (unsigned HOST_WIDE_INT) warn_alloca;
+  if (is_vla)
+    {
+      tree ptype = TREE_TYPE (gimple_call_lhs (stmt));
+      gcc_assert (TREE_CODE (ptype) == POINTER_TYPE);
+      gcc_assert (TREE_CODE (TREE_TYPE (ptype)) == ARRAY_TYPE);
+      tree inner_type = TREE_TYPE (TREE_TYPE (ptype));
+      tree unit = TYPE_SIZE_UNIT (inner_type);
+      max_size *= tree_to_uhwi (unit);
+    }
+
+  // Check for the obviously bounded case.
+  if (TREE_CODE (len) == INTEGER_CST)
+    {
+      if (tree_to_uhwi (len) > max_size)
+	return ALLOCA_BOUND_DEFINITELY_LARGE;
+      w = ALLOCA_OK;
+    }
+  else if (TREE_CODE (len) != SSA_NAME)
+    return ALLOCA_UNBOUNDED;
+  // Check the range info if available.
+  else
+    {
+      if (value_range_type range_type = get_range_info (len, &min, &max))
+	{
+	  if (range_type == VR_RANGE)
+	    {
+	      if (wi::leu_p (max, max_size))
+		w = ALLOCA_OK;
+	      else if (is_max (len, max))
+		{
+		  // A cast may have created a range we don't care
+		  // about.  For instance, a cast from 16-bit to
+		  // 32-bit creates a range of 0..65535, even if there
+		  // is not really a determinable range in the
+		  // underlying code.  In this case, look through the
+		  // cast at the original argument, and fall through
+		  // to look at other alternatives.
+		  gimple *def = SSA_NAME_DEF_STMT (len);
+		  if (gimple_assign_cast_p (def))
+		    len = gimple_assign_rhs1 (def);
+		}
+	      else
+		{
+		  /* If `len' is merely a cast that is being
+		     calculated right before the call to alloca, look
+		     at the range for the original value.
+
+		     This avoids the cast creating a range where the
+		     original expression did not have a range:
+
+		     # RANGE [0, 18446744073709551615] NONZERO 4294967295
+		     _2 = (long unsigned int) n_7(D);
+		     p_9 = __builtin_alloca (_2);
+
+		     The correct thing would've been for the user to
+		     use size_t, which in the case above would've been
+		     'long unsigned int', and everything would've
+		     worked.  But we have to catch cases where the
+		     user is using some other compatible type for the
+		     call argument to alloca (say unsigned short).  */
+		  gimple *def = SSA_NAME_DEF_STMT (len);
+		  if (gimple_assign_cast_p (def))
+		    {
+		      len = gimple_assign_rhs1 (def);
+		      range_type = get_range_info (len, &min, &max);
+		    }
+
+		  if (range_type != VR_VARYING && is_max (len, max))
+		    {
+		      // Treat a max of the entire domain as if it had no
+		      // range info, and fall through the try other
+		      // alternatives.
+		    }
+		  else
+		    return ALLOCA_BOUND_MAYBE_LARGE;
+		}
+	    }
+	  else if (range_type == VR_ANTI_RANGE)
+	    {
+	      // There may be some wrapping around going on.
+	      if (cast_from_signed_p (len))
+		return ALLOCA_CAST_FROM_SIGNED;
+	      // Fall thru and try other things.
+	    }
+	  else if (range_type == VR_VARYING)
+	    {
+	      // No easily determined range.  Try other things.
+	    }
+	}
+    }
+
+  // If we couldn't find anything, try a few heuristics for things we
+  // can easily determine.  Check these misc cases but only accept
+  // them if all predecessors have a known bound.
+  if (w == ALLOCA_UNBOUNDED)
+    {
+      w = ALLOCA_OK;
+      for (unsigned ix = 0; ix < EDGE_COUNT (bb->preds); ix++)
+	{
+	  enum alloca_type w
+	    = alloca_call_type_by_arg (len, EDGE_PRED (bb, ix), max_size);
+	  if (w != ALLOCA_OK)
+	    return w;
+	}
+    }
+
+  return w;
+}
+
+static inline const char *
+alloca_str (bool is_vla)
+{
+  return is_vla ? "variable-length array" : "alloca";
+}
+
+// Return the warning code for -Walloca or -Wvla depending on whether
+// we are talking about a VLA.
+
+static inline enum opt_code
+Wcode (bool is_vla)
+{
+  return is_vla ? OPT_Wvla : OPT_Walloca;
+}
+
+unsigned int
+pass_walloca::execute (function *fun)
+{
+  basic_block bb;
+  FOR_EACH_BB_FN (bb, fun)
+    {
+      for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);
+	   gsi_next (&si))
+	{
+	  gimple *stmt = gsi_stmt (si);
+	  location_t loc = gimple_location (stmt);
+
+	  if (!gimple_alloca_call_p (stmt))
+	    continue;
+	  gcc_assert (gimple_call_num_args (stmt) >= 1);
+
+	  // GCC emits two types of __builtin_alloca's, the
+	  // traditional __builtin_alloca and a
+	  // __builtin_alloca_with_align.  The latter gets generated
+	  // for VLA's, which means we can kill two birds with one
+	  // code.
+	  bool is_vla = DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))
+					    == BUILT_IN_ALLOCA_WITH_ALIGN;
+
+	  // Strict mode whining for VLAs is handled by the front-end.
+	  if (is_vla && (!warn_vla || vla_strict_mode))
+	    continue;
+
+	  // Strict mode; warn on all alloca uses.
+	  if (!is_vla && (!warn_alloca || alloca_strict_mode))
+	    {
+	      if (alloca_strict_mode)
+		warning_at (loc, OPT_Walloca, "use of alloca");
+	      continue;
+	    }
+
+	  enum alloca_type w = alloca_call_type (stmt, is_vla);
+	  switch (w)
+	    {
+	    case ALLOCA_OK:
+	      break;
+	    case ALLOCA_BOUND_MAYBE_LARGE:
+	      warning_at (loc, Wcode (is_vla),
+			  "argument to %s may be too large",
+			  alloca_str (is_vla));
+	      break;
+	    case ALLOCA_BOUND_DEFINITELY_LARGE:
+	      warning_at (loc, Wcode (is_vla),
+			  "argument to %s is too large",
+			  alloca_str (is_vla));
+	      break;
+	    case ALLOCA_BOUND_UNKNOWN:
+	      warning_at (loc, Wcode (is_vla), "%s bound is unknown",
+			  alloca_str (is_vla));
+	      break;
+	    case ALLOCA_UNBOUNDED:
+	      warning_at (loc, Wcode (is_vla), "unbounded use of %s",
+			  alloca_str (is_vla));
+	      break;
+	    case ALLOCA_IN_LOOP:
+	      warning_at (loc, Wcode (is_vla), "use of %s within a loop",
+			  alloca_str (is_vla));
+	      break;
+	    case ALLOCA_CAST_FROM_SIGNED:
+	      warning_at (loc, Wcode (is_vla), "cast from signed type "
+			  "in %s", alloca_str (is_vla));
+	      break;
+	    default:
+	      gcc_unreachable ();
+	    }
+	}
+    }
+  return 0;
+}
+
+gimple_opt_pass *
+make_pass_walloca (gcc::context *ctxt)
+{
+  return new pass_walloca (ctxt);
+}
diff --git a/gcc/opts.c b/gcc/opts.c
index e80331f..74278a4 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -743,6 +743,28 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
   if (opts->x_flag_tm && opts->x_flag_non_call_exceptions)
     sorry ("transactional memory is not supported with non-call exceptions");
 
+  /* -Walloca needs range info which is only available at -O2.  We
+      could theoretically run -Walloca with -O1, because plain
+      -Walloca warns on everything (and doesn't need range info).
+      However, the pass itself gets run within the
+      `pass_all_optimizations' framework in passes.def, which gets run
+      at -O1 and above.  To simplify matters, just bail.  */
+  if (opts->x_optimize < 2
+      && (opts->x_warn_alloca == -2
+	  || opts->x_warn_alloca > 0))
+    {
+      sorry ("-Walloca ignored without -O2");
+      opts->x_warn_alloca = 0;
+    }
+
+  /* -Wvla= needs range info which is only available at -O2.  */
+  if (opts->x_optimize < 2
+      && opts->x_warn_vla > 0)
+    {
+      sorry ("-Wvla= ignored without -O2");
+      opts->x_warn_vla = 0;
+    }
+
   /* Unless the user has asked for section anchors, we disable toplevel
      reordering at -O0 to disable transformations that might be surprising
      to end users and to get -fno-toplevel-reorder tested.  */
@@ -1777,6 +1799,20 @@ common_handle_option (struct gcc_options *opts,
       /* Currently handled in a prescan.  */
       break;
 
+    case OPT_Walloca:
+      /* Plain -Walloca will set warn_alloca to 1, but this conflicts
+         with -Walloca=1, and we can't tell the difference.  Set to -2
+         here which means -Walloca was set with no argument.  */
+      if (value == 1)
+	warn_alloca = -2;
+      break;
+
+    case OPT_Walloca_:
+      if (value == 0)
+	inform (loc,
+		"-Walloca=0 disables -Walloca.  Use -Wno-alloca instead.");
+      break;
+
     case OPT_Werror:
       dc->warning_as_error_requested = value;
       break;
diff --git a/gcc/passes.def b/gcc/passes.def
index 3647e90..4b503e8 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -303,6 +303,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_simduid_cleanup);
       NEXT_PASS (pass_lower_vector_ssa);
       NEXT_PASS (pass_cse_reciprocals);
+      NEXT_PASS (pass_walloca);
       NEXT_PASS (pass_reassoc, false /* insert_powi_p */);
       NEXT_PASS (pass_strength_reduction);
       NEXT_PASS (pass_split_paths);
diff --git a/gcc/testsuite/gcc.dg/Walloca-1.c b/gcc/testsuite/gcc.dg/Walloca-1.c
new file mode 100644
index 0000000..dc7b2a9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-1.c
@@ -0,0 +1,49 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca=2000 -O2" } */
+
+#define alloca __builtin_alloca
+
+typedef __SIZE_TYPE__ size_t;
+extern size_t strlen(const char *);
+
+extern void useit (char *);
+
+int num;
+
+void test_walloca (size_t len, size_t len2, size_t len3)
+{
+  int i;
+
+  for (i=0; i < 123; ++i)
+    {
+      char *s = alloca (566);	/* { dg-warning "alloca within a loop" } */
+      useit (s);
+    }
+
+  char *s = alloca (123);
+  useit (s);			// OK, constant argument to alloca
+
+  s = alloca (num);		// { dg-warning "cast from signed type in alloca" }
+  useit (s);
+
+  s = alloca(90000);		/* { dg-warning "is too large" } */
+  useit (s);
+
+  if (len < 2000)
+    {
+      s = alloca(len);		// OK, bounded
+      useit (s);
+    }
+
+  if (len + len2 < 2000)	// OK, bounded
+    {
+      s = alloca(len + len2);
+      useit (s);
+    }
+
+  if (len3 <= 2001)
+    {
+      s = alloca(len3);		/* { dg-warning "may be too large" } */
+      useit(s);
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-2.c b/gcc/testsuite/gcc.dg/Walloca-2.c
new file mode 100644
index 0000000..dcf3959
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-2.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca=2000 -O2" } */
+
+void f (void *);
+
+void
+g1 (int n)
+{
+  void *p;
+  if (n > 0 && n < 2000)
+    p = __builtin_alloca (n);
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
+
+void
+g2 (int n)
+{
+  void *p;
+  if (n < 2000)
+    p = __builtin_alloca (n); // { dg-warning "cast from signed type in alloca" }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
+
+void
+g3 (int n)
+{
+  void *p;
+  if (n > 0 && n < 3000)
+    p = __builtin_alloca (n); // { dg-warning "alloca may be too large" }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-3.c b/gcc/testsuite/gcc.dg/Walloca-3.c
new file mode 100644
index 0000000..16466fa
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-3.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca=2000 -O2" } */
+
+void f (void *);
+
+__SIZE_TYPE__ LIMIT;
+
+// Warn when there is an alloca bound, but it is an unknown bound.
+
+void
+g1 (__SIZE_TYPE__ n)
+{
+  void *p;
+  if (n < LIMIT)
+    p = __builtin_alloca (n); // { dg-warning "alloca bound is unknown" }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
+
+// Similar to the above, but do not get confused by the upcast.
+
+unsigned short SHORT_LIMIT;
+void
+g2 (unsigned short n)
+{
+  void *p;
+  if (n < SHORT_LIMIT)
+    p = __builtin_alloca (n); // { dg-warning "alloca bound is unknown" }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-4.c b/gcc/testsuite/gcc.dg/Walloca-4.c
new file mode 100644
index 0000000..f910a8d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-4.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca=5000 -O2" } */
+/* { dg-xfail-if "Currently broken but Andrew's work should fix this" { *-*-* } } */
+
+// Should be another variant of Walloca-7.c.
+// This should not warn, as we have a known bound within limits.
+
+ char *
+ _i18n_number_rewrite (char *w, char *rear_ptr)
+{
+
+  char *src;
+ _Bool 
+      use_alloca = (((rear_ptr - w) * sizeof (char)) < 4096U);
+ if (use_alloca)
+    src = (char *) __builtin_alloca ((rear_ptr - w) * sizeof (char));
+  else
+    src = (char *) __builtin_malloc ((rear_ptr - w) * sizeof (char));
+  return src;
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-5.c b/gcc/testsuite/gcc.dg/Walloca-5.c
new file mode 100644
index 0000000..60d5715
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-5.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca -O2" } */
+/* { dg-xfail-if "Currently broken but Andrew's work should fix this" { *-*-* } } */
+
+/* The argument to alloca ends up having a range of 0..MAXINT(32bits),
+   so we think we have a range because of the upcast.  Consequently,
+   we warn with "alloca may be too large", but we should technically
+   warn with "unbounded use of alloca".
+
+   We currently drill through casts to figure this stuff out, but we
+   get confused because it's not just a cast.  It's a cast, plus a
+   multiply.
+
+   <bb 2>:
+  # RANGE [0, 4294967295] NONZERO 4294967295
+  _1 = (long unsigned int) something_4(D);
+  # RANGE [0, 34359738360] NONZERO 34359738360
+  _2 = _1 * 8;
+  _3 = __builtin_alloca (_2);
+
+  I don't know whether it's even worth such fine-grained warnings.
+  Perhaps we should generically warn everywhere with "alloca may be
+  too large".
+
+  I'm hoping that this particular case will be easier to diagnose with
+  Andrew's work.  */
+
+void useit(void *);
+void foobar(unsigned int something)
+{
+  useit(__builtin_alloca (something * sizeof (const char *))); // { dg-warning "unbounded use of alloca" "" { xfail *-*-* } }
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-6.c b/gcc/testsuite/gcc.dg/Walloca-6.c
new file mode 100644
index 0000000..e89e74b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-6.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca -O2" } */
+/* { dg-xfail-if "Currently broken but Andrew's work should fix this" { *-*-* } } */
+
+void f (void*);
+void g (__SIZE_TYPE__ n)
+{
+  // No warning on this case.  Range is easily determinable.
+  if (n > 0 && n < 256)
+    f (__builtin_alloca (n));
+}
diff --git a/gcc/testsuite/gcc.dg/Wvla-1.c b/gcc/testsuite/gcc.dg/Wvla-1.c
new file mode 100644
index 0000000..a1b939f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wvla-1.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-Wvla=100 -O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern void useit (char *);
+
+int num;
+
+void test_vlas (size_t num)
+{
+  char str2[num];		/* { dg-warning "unbounded use" } */
+  useit(str2);
+
+  num = 98;
+  for (int i=0; i < 1234; ++i) {
+    char str[num];	        // OK, VLA in a loop, but it is a
+				// known size *AND* the compiler takes
+				// care of cleaning up between
+				// iterations with
+				// __builtin_stack_restore.
+    useit(str);
+  }
+}
diff --git a/gcc/testsuite/gcc.dg/Wvla-2.c b/gcc/testsuite/gcc.dg/Wvla-2.c
new file mode 100644
index 0000000..353bf58
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wvla-2.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-Wvla=2000 -O2" } */
+
+void f (void*);
+
+void h1 (unsigned n)
+{
+  if (n <= 2001)
+    {
+      int a [n]; // { dg-warning "variable-length array may be too large" }
+      f (a);
+    }
+}
+
+void h2 (unsigned n)
+{
+  if (n <= 2000)
+    {
+      int a [n];
+      f (a);
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/Wvla-3.c b/gcc/testsuite/gcc.dg/Wvla-3.c
new file mode 100644
index 0000000..5124476
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wvla-3.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca -O2" } */
+
+// Make sure we don't warn on VLA with -Walloca.
+
+void f (void*);
+
+void h1 (unsigned n)
+{
+  int a [n];
+  f (a);
+}
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 36299a6..57b61f4 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -469,6 +469,7 @@ extern simple_ipa_opt_pass *make_pass_ipa_oacc (gcc::context *ctxt);
 extern simple_ipa_opt_pass *make_pass_ipa_oacc_kernels (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_gen_hsail (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_warn_nonnull_compare (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_walloca (gcc::context *ctxt);
 
 /* IPA Passes */
 extern simple_ipa_opt_pass *make_pass_ipa_lower_emutls (gcc::context *ctxt);

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-08 11:48 RFA: new pass to warn on questionable uses of alloca() and VLAs Aldy Hernandez
@ 2016-07-10 22:09 ` Martin Sebor
  2016-07-11 14:32   ` Jeff Law
  2016-07-15 17:05   ` Aldy Hernandez
  2016-07-10 23:41 ` Manuel López-Ibáñez
  2016-07-11 14:25 ` Jeff Law
  2 siblings, 2 replies; 26+ messages in thread
From: Martin Sebor @ 2016-07-10 22:09 UTC (permalink / raw)
  To: Aldy Hernandez, gcc-patches, Martin Sebor, Jeff Law; +Cc: Andrew MacLeod

On 07/08/2016 05:48 AM, Aldy Hernandez wrote:
> [New thread now that I actually have a tested patch :)].
...
> I have overhauled the options and added extensive documentation to
> invoke.texi explaining them.  See the included testcases.  I have tried
> to add a testcase for everything the pass currently handles.
>
> In the interest of keeping a consistent relationship with -Wvla, we now
> have:
>
> -Walloca:    Warn on every use of alloca (not VLAs).
> -Walloca=999:    Warn on unbounded uses of alloca, bounded uses with
>          no known limit, and bounded uses where the number of
>          bytes is greater than 999.
> -Wvla:        Behaves as currently (warn on every use of VLAs).
> -Wvla=999:    Similar to -Walloca=999, but for -Wvla.
>
> Notice plain -Walloca doesn't have a default, and just warns on every
> use of alloca, just like -Wvla does for VLAs.  This way we can be
> consistent with -Wvla, and just add the -Wvla=999 variant.

I like it!

> This patch depends on range information, which is less than stellar past
> the VRP pass.  To get better range information, we'd have to incorporate
> this somehow into the VRP pass and use the ASSERT_EXPRs therein.  And
> still, VRP gets awfully confused with PHI merge points.  Andrew Macleod
> is working on a new fancy range info infrastructure that should
> eliminate a lot of the false positives we may get and/or help us
> diagnose a wider range of cases.  Hence the reason that I'm not bending
> over backwards to incorporate this pass into tree-vrp.c.
>
> FYI, I have a few XFAILed tests in this patch, to make sure we don't
> lose track of possible improvements (which in this case should be
> handled by better range info).  What's the blessed way of doing this?
> Are adding new XFAILed tests acceptable?
>
> I have regstrapped this patch on x86-64 Linux, and have tested the
> resulting compiler by building glibc with:
>
> /source/glibc/configure --prefix=/usr CC="/path/bin/gcc -Walloca=5000"
> --disable-werror
>
> This of course, pointed out all sorts of interesting things!
>
> Fire away!

I've played with the patch a bit over the weekend and have a few
comments and suggestions (I hope you won't regret encouraging me :)
I like the consistency between -Walloca and -Wvla! (And despite
the volume of my remaining comments, the rest of the patch too!

1) Optimization.  Without -O2 GCC prints:

   sorry, unimplemented: -Walloca ignored without -O2

It seems that a warning would be more appropriate here than
a hard error, but the checker could, and I would say should, be
made available (in a limited form) without optimization because
  -Walloca with no argument doesn't rely on it.  I suspect in this
form, -Walloca is probably mainly going to be useful as a mechanism
to enforce a "thou shall not use alloca" policy, though not much
more beyond that.  Some development processes only require that
code build without optimization in order to allow a commit and
do more extensive testing with optimization during continuous
integration, and not enabling it at -O0 would make it difficult
to adopt the warning on projects that use such a process.

2) When passed an argument of a signed type, GCC prints

   warning: cast from signed type in alloca

even though there is no explicit cast in the code.  It may not
be obvious why the conversion is a problem in this context.  I
would suggest to rephrase the warning along the lines of
-Wsign-conversion which prints:

   conversion to ‘long unsigned int’ from ‘int’ may change the sign of 
the result

and add why it's a potential problem.  Perhaps something like:

   argument to alloca may be too large due to conversion from
   'int to 'long unsigned int'

(In addition, assuming one accepts the lack of range checking and
constant propagation, this aspect of -Walloca also doesn't need
optimization.)

3) I wonder if the warning should also detect alloca calls with
a zero argument and VLAs of zero size.  They are both likely to
be programmer errors.  (Although it seems that that would need
to be done earlier than in the alloca pass.)

4) I wasn't able to trigger the -Wvla=N warning with VLAs used
in loops even though VRP provides the range of the value:

   $ cat t.c && /build/gcc-walloca/gcc/xgcc -B /build/gcc-walloca/gcc 
-O2 -S -Wall -Wextra -Wpedantic -Wvla=3 -fdump-tree-vrp=/dev/stdout t.c 
| grep _2
   void f0 (void*);

   void f1 (void)
   {
     for (int i = 0; i != 32; ++i)
     {
       char a [i];
       f0 (a);
     }
   }

   _2: [0, 31]
     sizetype _2;
     _2 = (sizetype) i_16;
     a.1_8 = __builtin_alloca_with_align (_2, 8);

5) The -Wvla=N logic only seems to take into consideration the number
of elements but not the size of the element type. For example, I wasn't
able to get it to warn on the following with -Wvla=255 or greater:

   void f0 (void*);

   void f1 (unsigned char a)
   {
     int x [a];   // or even char a [n][__INT_MAX__];
     f0 (x);
   }

6) The patch seems to assume that __builtin_alloca_with_align implies
a VLA, but that need not be the case.  Based on tree dumps it looks
like there is a way to distinguish a VLA from a call to the built-in.
For accuracy's sake I think it would be worth making that distinction
in the diagnostic.

7) The -Walloca=N and -Wvla=N argument is a 32-bit integer and no
checking appears to be done to make sure it doesn't overflow, so
that invoking GCC with an argument of UINT_MAX results in:

   cc1: note: -Wvla=0 disables -Wvla.  Use -Wno-vla instead.

and with larger arguments in imposing a limit that's modulo UINT_MAX.
Although stack size in excess of UINT_MAX bytes is unlikely, it seems
that such exceedingly large arguments should be handled more gracefully
(if they cannot be stored in a size_t argument it would be nice give
a warning).

8) Finally, I think it would be helpful to provide information about
the values GCC used to decide to issue the warning, especially when
optimization is involved.  In many cases it will not be immediately
obvious how GCC determined that an alloca argument is too big, or
what the limit even is (for instance, when the -Walloca=N option
is set via a #pragma GCC diagnostic far away from the call).
Mentioning both the argument value or range and the threshold for
the warning will help make it clear.

Martin

PS I also ran into a couple internal compiler errors with the test
cases below:

   void f0 (void*);

   void f1 (int a, int b)
   {
     int x [a][b];
     f0 (x);
   }

   0x11def63 tree_to_uhwi(tree_node const*)
   /src/gcc/walloca/gcc/tree.c:7339
   ...

   void f0 (void*);

   void f1 (unsigned char a)
   {
     void *p = __builtin_alloca_with_align (a, 8);
     f0 (p);
   }

   x181cb74 alloca_call_type
   /src/gcc/walloca/gcc/gimple-ssa-warn-alloca.c:257
   ...

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-08 11:48 RFA: new pass to warn on questionable uses of alloca() and VLAs Aldy Hernandez
  2016-07-10 22:09 ` Martin Sebor
@ 2016-07-10 23:41 ` Manuel López-Ibáñez
  2016-07-11 10:10   ` Aldy Hernandez
  2016-07-11 14:25 ` Jeff Law
  2 siblings, 1 reply; 26+ messages in thread
From: Manuel López-Ibáñez @ 2016-07-10 23:41 UTC (permalink / raw)
  To: Aldy Hernandez, gcc-patches, Martin Sebor, Jeff Law; +Cc: Andrew MacLeod

> +Walloca
> +LangEnabledBy(C ObjC C++ ObjC++)
> +; in common.opt
> +
> +Walloca=
> +LangEnabledBy(C ObjC C++ ObjC++)
> +; in common.opt
> +

I'm not sure what you think the above means, but this is an invalid use of 
LangEnabledBy(). (It would be nice if the .awk scripts were able to catch it 
and give an error.)


> +;; warn_vla == 0 for -Wno-vla
> +;; warn_vla == -1 for nothing passed.
> +;; warn_vla == -2 for -Wvla passed
> +;; warn_vla == NUM for -Wvla=NUM
>  Wvla
>  C ObjC C++ ObjC++ Var(warn_vla) Init(-1) Warning
>  Warn if a variable length array is used.
>
> +Wvla=
> +C ObjC C++ ObjC++ Var(warn_vla) Warning Joined RejectNegative UInteger
> +-Wvla=<number> Warn on unbounded uses of variable-length arrays, and
> +warn on bounded uses of variable-length arrays whose bound can be
> +larger than <number> bytes.
> +

This overloading of warn_vla seems confusing (as shown by all the places that 
require updating). Why not call it Wvla-larger-than= and use a different 
warn_vla_larger_than variable? We already have -Wlarger-than= and 
-Wframe-larger-than=.

Using warn_vla_larger_than (even if you wish to keep -Wvla= as the option name) 
as a variable distinct from warn_vla would make things simpler:

-Wvla => warn_vla == 1
-Wno-vla => warn_vla == 0
-Wvla=N => warn_vla_larger_than == N (where N == 0 means disable).

If you wish that -Wno-vla implies -Wvla=0 then you'll need to handle that 
manually. I don't think we have support for that in the .opt files. But that 
seems far less complex than having a single shared Var().

Cheers,
	Manuel.

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-10 23:41 ` Manuel López-Ibáñez
@ 2016-07-11 10:10   ` Aldy Hernandez
  2016-07-11 14:22     ` Manuel López-Ibáñez
  2016-07-11 15:08     ` Martin Sebor
  0 siblings, 2 replies; 26+ messages in thread
From: Aldy Hernandez @ 2016-07-11 10:10 UTC (permalink / raw)
  To: Manuel López-Ibáñez, gcc-patches, Martin Sebor, Jeff Law
  Cc: Andrew MacLeod

On 07/10/2016 07:41 PM, Manuel López-Ibáñez wrote:
>> +Walloca
>> +LangEnabledBy(C ObjC C++ ObjC++)
>> +; in common.opt
>> +
>> +Walloca=
>> +LangEnabledBy(C ObjC C++ ObjC++)
>> +; in common.opt
>> +
>
> I'm not sure what you think the above means, but this is an invalid use
> of LangEnabledBy(). (It would be nice if the .awk scripts were able to
> catch it and give an error.)

I was following the practice for -Warray-bounds in c-family/c.opt:

Warray-bounds
LangEnabledBy(C ObjC C++ ObjC++,Wall)
; in common.opt

Warray-bounds=
LangEnabledBy(C ObjC C++ ObjC++,Wall,1,0)
; in common.opt

...as well as the generic version in common.opt:

Warray-bounds
Common Var(warn_array_bounds) Warning
Warn if an array is accessed out of bounds.

Warray-bounds=
Common Joined RejectNegative UInteger Var(warn_array_bounds) Warning
Warn if an array is accessed out of bounds.

I *thought* you defined the option in common.opt, and narrowed the 
language variants in c-family/c.opt.  ??

>
>
>> +;; warn_vla == 0 for -Wno-vla
>> +;; warn_vla == -1 for nothing passed.
>> +;; warn_vla == -2 for -Wvla passed
>> +;; warn_vla == NUM for -Wvla=NUM
>>  Wvla
>>  C ObjC C++ ObjC++ Var(warn_vla) Init(-1) Warning
>>  Warn if a variable length array is used.
>>
>> +Wvla=
>> +C ObjC C++ ObjC++ Var(warn_vla) Warning Joined RejectNegative UInteger
>> +-Wvla=<number> Warn on unbounded uses of variable-length arrays, and
>> +warn on bounded uses of variable-length arrays whose bound can be
>> +larger than <number> bytes.
>> +
>
> This overloading of warn_vla seems confusing (as shown by all the places
> that require updating). Why not call it Wvla-larger-than= and use a
> different warn_vla_larger_than variable? We already have -Wlarger-than=
> and -Wframe-larger-than=.

Hey, I'm all for different options.  It would definitely be easier for 
me :).  I wast trying really hard to use -Wvla= and keep the current 
-Wvla meaning the same.  Though I see your point about using -Wvla* but 
using different variables for representing -Wvla and -Wvla=blah.

The easiest thing would be:

-Wvla: Current behavior (warn on everything).

-Wvla-larger-than=xxxx: Warn on unbounded VLA and bounded VLAs > xxxx.

-Walloca: Warn on every use of alloca (analogous to -Wvla).

-Walloca-larger-than=xxxx: Warn on unbounded alloca and bounded allocas 
 > xxxx.

This seems straightforward and avoids all the overloading you see. 
Would this be ok with everyone?

>
> Using warn_vla_larger_than (even if you wish to keep -Wvla= as the
> option name) as a variable distinct from warn_vla would make things
> simpler:
>
> -Wvla => warn_vla == 1
> -Wno-vla => warn_vla == 0
> -Wvla=N => warn_vla_larger_than == N (where N == 0 means disable).
>
> If you wish that -Wno-vla implies -Wvla=0 then you'll need to handle
> that manually. I don't think we have support for that in the .opt files.
> But that seems far less complex than having a single shared Var().
>
> Cheers,
>      Manuel.
>

Thanks.
Aldy

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-11 10:10   ` Aldy Hernandez
@ 2016-07-11 14:22     ` Manuel López-Ibáñez
  2016-07-11 15:08     ` Martin Sebor
  1 sibling, 0 replies; 26+ messages in thread
From: Manuel López-Ibáñez @ 2016-07-11 14:22 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: gcc-patches, Martin Sebor, Jeff Law, Andrew MacLeod

On 11 July 2016 at 11:10, Aldy Hernandez <aldyh@redhat.com> wrote:
> On 07/10/2016 07:41 PM, Manuel López-Ibáñez wrote:
>>>
>>> +Walloca
>>> +LangEnabledBy(C ObjC C++ ObjC++)
>>> +; in common.opt
>>> +
>>> +Walloca=
>>> +LangEnabledBy(C ObjC C++ ObjC++)
>>> +; in common.opt
>>> +
>>
>>
>> I'm not sure what you think the above means, but this is an invalid use
>> of LangEnabledBy(). (It would be nice if the .awk scripts were able to
>> catch it and give an error.)
>
>
> I was following the practice for -Warray-bounds in c-family/c.opt:
>
> Warray-bounds
> LangEnabledBy(C ObjC C++ ObjC++,Wall)
> ; in common.opt
>
> Warray-bounds=
> LangEnabledBy(C ObjC C++ ObjC++,Wall,1,0)
> ; in common.opt

The ones you quoted mean: For that list of languages, -Warray-bounds
is enabled by -Wall.

https://gcc.gnu.org/onlinedocs/gccint/Option-properties.html#Option-properties

But the entries that you added do not specify an option. It should
give an error by the *.awk scripts that parse .opt files. I'm actually
not sure what the scripts are generating in your case.

> I *thought* you defined the option in common.opt, and narrowed the language
> variants in c-family/c.opt.  ??

No, options that are language specific just need to be defined for the
respective FEs using the respective language flags: Wvla is an example
of that. It doesn't appear in common.opt.

Adding language flags to a common option is just redundant (again,
this is not what LangEnabledBy is doing).

Cheers,

Manuel.

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-08 11:48 RFA: new pass to warn on questionable uses of alloca() and VLAs Aldy Hernandez
  2016-07-10 22:09 ` Martin Sebor
  2016-07-10 23:41 ` Manuel López-Ibáñez
@ 2016-07-11 14:25 ` Jeff Law
  2 siblings, 0 replies; 26+ messages in thread
From: Jeff Law @ 2016-07-11 14:25 UTC (permalink / raw)
  To: Aldy Hernandez, gcc-patches, Martin Sebor; +Cc: Andrew MacLeod

On 07/08/2016 05:48 AM, Aldy Hernandez wrote:
> [New thread now that I actually have a tested patch :)].
>
>> I think detecting potentially problematic uses of alloca would
>> be useful, especially when done in an intelligent way like in
>> your patch (as opposed to simply diagnosing every call to
>> the function regardless of the value of its argument).  At
>> the same time, it seems that an even more reliable solution
>> than pointing out potentially unsafe calls to the function
>> and relying on users to modify their code to use malloc for
>> large/unbounded allocations would be to let GCC do it for
>> them automatically (i.e., in response to some other option,
>> emit a call to malloc instead, and insert a call to free when
>> appropriate).
>
> As Jeff said, we were thinking the other way around: notice a malloced
> area that doesn't escape and replace it with a call to alloca.  But all
> this is beyond the scope of this patch.
Definitely out of scope for this set of changes.    BUt it's part of my 
evil plan to squash explicit alloca calls while still allowing its use 
when it's provably safe.  But we're not in that world yet.

>> I found the "warning: unbounded use of alloca" misleading when
>> a call to the function was, in fact, bounded but to a limit
>> that's greater than alloca-max-size as in the program below:
>
> I have added various levels of granularity for the warning, along with
> appropriately different messages:
>
> // Possible problematic uses of alloca.
> enum alloca_type {
>   // Alloca argument is within known bounds that are appropriate.
>   ALLOCA_OK,
>
>   // Alloca argument is KNOWN to have a value that is too large.
>   ALLOCA_BOUND_DEFINITELY_LARGE,
>
>   // Alloca argument may be too large.
>   ALLOCA_BOUND_MAYBE_LARGE,
>
>   // Alloca argument is bounded but of an indeterminate size.
>   ALLOCA_BOUND_UNKNOWN,
>
>   // Alloca argument was casted from a signed integer.
>   ALLOCA_CAST_FROM_SIGNED,
>
>   // Alloca appears in a loop.
>   ALLOCA_IN_LOOP,
>
>   // Alloca call is unbounded.  That is, there is no controlling
>   // predicate for its argument.
>   ALLOCA_UNBOUNDED
> };
>
> Of course, there are plenty of cases where we can't get the exact
> diagnosis (due to the limitations on our range info) and we fall back to
> ALLOCA_UNBOUNDED or ALLOCA_BOUND_MAYBE_LARGE.  In practice, I'm
> wondering whether we should lump everything into 2-3 warnings instead of
> trying so hard to get the exact reason for the problematic use of
> alloca.  (More details on upcoming changes to range info further down.)
I'll trust your judgment on this -- I kind of like the more precise 
warnings -- if for no other reason than it makes it easier for someone 
looking at legacy code (think glibc) to see why GCC determined their 
alloca call was unsafe.

>
>>
>>   void f (void*);
>>
>>   void g (int n)
>>   {
>>     void *p;
>>     if (n < 4096)
>>       p = __builtin_alloca (n);
>>     else
>>       p = __builtin_malloc (n);
>>     f (p);
>>   }
>>   t.C: In function ‘g’:
>>   t.C:7:7: warning: unbounded use of alloca [-Walloca]
>>        p = __builtin_alloca (n);
>
> Well, in this particular case you are using a signed int, so n < 4096
> can cause the value passed to alloca  to be rather large in the case of
> n < 0.
Right.  And if the bad guys can get control of "N" in this case, they 
can pass in a negative value and perform a "stack shift" -- essentially 
moving the stack so that it points somewhere else  more "interesting" in 
memory.


>
> This patch depends on range information, which is less than stellar past
> the VRP pass.  To get better range information, we'd have to incorporate
> this somehow into the VRP pass and use the ASSERT_EXPRs therein.  And
> still, VRP gets awfully confused with PHI merge points.  Andrew Macleod
> is working on a new fancy range info infrastructure that should
> eliminate a lot of the false positives we may get and/or help us
> diagnose a wider range of cases.  Hence the reason that I'm not bending
> over backwards to incorporate this pass into tree-vrp.c.
Right.  Getting better range information is important in so many ways.

>
> FYI, I have a few XFAILed tests in this patch, to make sure we don't
> lose track of possible improvements (which in this case should be
> handled by better range info).  What's the blessed way of doing this?
> Are adding new XFAILed tests acceptable?
I'd go with a new XFAIL'd test.

Jeff

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-10 22:09 ` Martin Sebor
@ 2016-07-11 14:32   ` Jeff Law
  2016-07-15 17:05   ` Aldy Hernandez
  1 sibling, 0 replies; 26+ messages in thread
From: Jeff Law @ 2016-07-11 14:32 UTC (permalink / raw)
  To: Martin Sebor, Aldy Hernandez, gcc-patches, Martin Sebor; +Cc: Andrew MacLeod

On 07/10/2016 04:09 PM, Martin Sebor wrote:
> On 07/08/2016 05:48 AM, Aldy Hernandez wrote:
>
> I've played with the patch a bit over the weekend and have a few
> comments and suggestions (I hope you won't regret encouraging me :)
> I like the consistency between -Walloca and -Wvla! (And despite
> the volume of my remaining comments, the rest of the patch too!
>
> 1) Optimization.  Without -O2 GCC prints:
>
>   sorry, unimplemented: -Walloca ignored without -O2
>
> It seems that a warning would be more appropriate here than
> a hard error, but the checker could, and I would say should, be
> made available (in a limited form) without optimization because
>  -Walloca with no argument doesn't rely on it.  I suspect in this
> form, -Walloca is probably mainly going to be useful as a mechanism
> to enforce a "thou shall not use alloca" policy, though not much
> more beyond that.
:-)  Which would be fine with me -- the difference is, we'd be able to 
back up my "programmers can't correctly use alloca" rant from several 
years ago with compiler analysis showing why each particular alloca was 
unsafe.

>
> 2) When passed an argument of a signed type, GCC prints
>
>   warning: cast from signed type in alloca
>
> even though there is no explicit cast in the code.  It may not
> be obvious why the conversion is a problem in this context.  I
> would suggest to rephrase the warning along the lines of
> -Wsign-conversion which prints:
>
>   conversion to ‘long unsigned int’ from ‘int’ may change the sign of
> the result
>
> and add why it's a potential problem.  Perhaps something like:
>
>   argument to alloca may be too large due to conversion from
>   'int to 'long unsigned int'
I like Martin's much better.

>
> 3) I wonder if the warning should also detect alloca calls with
> a zero argument and VLAs of zero size.  They are both likely to
> be programmer errors.  (Although it seems that that would need
> to be done earlier than in the alloca pass.)
Seems like Aldy ought to add this as a testcase, even if it's XFAIL'd 
for now.

>
> 4) I wasn't able to trigger the -Wvla=N warning with VLAs used
> in loops even though VRP provides the range of the value:
Similarly for the others in your message.



Jeff

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-11 10:10   ` Aldy Hernandez
  2016-07-11 14:22     ` Manuel López-Ibáñez
@ 2016-07-11 15:08     ` Martin Sebor
  2016-07-11 15:40       ` Aldy Hernandez
  1 sibling, 1 reply; 26+ messages in thread
From: Martin Sebor @ 2016-07-11 15:08 UTC (permalink / raw)
  To: Aldy Hernandez, Manuel López-Ibáñez, gcc-patches,
	Martin Sebor, Jeff Law
  Cc: Andrew MacLeod

>
> Hey, I'm all for different options.  It would definitely be easier for
> me :).  I wast trying really hard to use -Wvla= and keep the current
> -Wvla meaning the same.  Though I see your point about using -Wvla* but
> using different variables for representing -Wvla and -Wvla=blah.
>
> The easiest thing would be:
>
> -Wvla: Current behavior (warn on everything).
>
> -Wvla-larger-than=xxxx: Warn on unbounded VLA and bounded VLAs > xxxx.
>
> -Walloca: Warn on every use of alloca (analogous to -Wvla).
>
> -Walloca-larger-than=xxxx: Warn on unbounded alloca and bounded allocas
>  > xxxx.
>
> This seems straightforward and avoids all the overloading you see. Would
> this be ok with everyone?

I like the consistency.

Given the common root with -Wlarger-than=N, what do envision the effect
of setting -Wlarger-than=N to be on the two new options?

FWIW, I tend to view -Wlarger-than= and certainly -Wframe-larger-than=
not warning on alloca larger than N as a defect.  It could be fixed by
simply hooking -Walloca-larger-than= up to it.

   void f (void*);
   void g (void)
   {
     void *p = __builtin_alloca (1024);
     f (p);
   }

Martin

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-11 15:08     ` Martin Sebor
@ 2016-07-11 15:40       ` Aldy Hernandez
  2016-07-11 17:56         ` Martin Sebor
  0 siblings, 1 reply; 26+ messages in thread
From: Aldy Hernandez @ 2016-07-11 15:40 UTC (permalink / raw)
  To: Martin Sebor, Manuel López-Ibáñez, gcc-patches,
	Martin Sebor, Jeff Law
  Cc: Andrew MacLeod

On 07/11/2016 11:08 AM, Martin Sebor wrote:
>>
>> Hey, I'm all for different options.  It would definitely be easier for
>> me :).  I wast trying really hard to use -Wvla= and keep the current
>> -Wvla meaning the same.  Though I see your point about using -Wvla* but
>> using different variables for representing -Wvla and -Wvla=blah.
>>
>> The easiest thing would be:
>>
>> -Wvla: Current behavior (warn on everything).
>>
>> -Wvla-larger-than=xxxx: Warn on unbounded VLA and bounded VLAs > xxxx.
>>
>> -Walloca: Warn on every use of alloca (analogous to -Wvla).
>>
>> -Walloca-larger-than=xxxx: Warn on unbounded alloca and bounded allocas
>>  > xxxx.
>>
>> This seems straightforward and avoids all the overloading you see. Would
>> this be ok with everyone?
>
> I like the consistency.
>
> Given the common root with -Wlarger-than=N, what do envision the effect
> of setting -Wlarger-than=N to be on the two new options?
>
> FWIW, I tend to view -Wlarger-than= and certainly -Wframe-larger-than=
> not warning on alloca larger than N as a defect.  It could be fixed by
> simply hooking -Walloca-larger-than= up to it.

I'm not touching any of these independent options.  -Wvla-larger-than= 
and -Walloca-larger-than= will be implemented independently of whatever 
-Wlarger-than= and -Wframe-larger-than=.  Any problems with these last 
two options can be treated indpendently (PRs).

Aldy

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-11 15:40       ` Aldy Hernandez
@ 2016-07-11 17:56         ` Martin Sebor
  2016-07-15 17:05           ` Aldy Hernandez
  0 siblings, 1 reply; 26+ messages in thread
From: Martin Sebor @ 2016-07-11 17:56 UTC (permalink / raw)
  To: Aldy Hernandez, Manuel López-Ibáñez, gcc-patches,
	Martin Sebor, Jeff Law
  Cc: Andrew MacLeod

On 07/11/2016 09:40 AM, Aldy Hernandez wrote:
> On 07/11/2016 11:08 AM, Martin Sebor wrote:
>>>
>>> Hey, I'm all for different options.  It would definitely be easier for
>>> me :).  I wast trying really hard to use -Wvla= and keep the current
>>> -Wvla meaning the same.  Though I see your point about using -Wvla* but
>>> using different variables for representing -Wvla and -Wvla=blah.
>>>
>>> The easiest thing would be:
>>>
>>> -Wvla: Current behavior (warn on everything).
>>>
>>> -Wvla-larger-than=xxxx: Warn on unbounded VLA and bounded VLAs > xxxx.
>>>
>>> -Walloca: Warn on every use of alloca (analogous to -Wvla).
>>>
>>> -Walloca-larger-than=xxxx: Warn on unbounded alloca and bounded allocas
>>>  > xxxx.
>>>
>>> This seems straightforward and avoids all the overloading you see. Would
>>> this be ok with everyone?
>>
>> I like the consistency.
>>
>> Given the common root with -Wlarger-than=N, what do envision the effect
>> of setting -Wlarger-than=N to be on the two new options?
>>
>> FWIW, I tend to view -Wlarger-than= and certainly -Wframe-larger-than=
>> not warning on alloca larger than N as a defect.  It could be fixed by
>> simply hooking -Walloca-larger-than= up to it.
>
> I'm not touching any of these independent options.  -Wvla-larger-than=
> and -Walloca-larger-than= will be implemented independently of whatever
> -Wlarger-than= and -Wframe-larger-than=.  Any problems with these last
> two options can be treated indpendently (PRs).

Strictly speaking there is no defect in -Wframe-larger-than= because
it's documented not to warn for alloca or VLAs.  I asked because it
seems like an unnecessary (and IMO undesirable) limitation that could
be easily removed as part of this patch.  Not removing it, OTOH, and
providing a separate solution, feels like highlighting the limitation.
With the new options, users interested in detecting all forms of
excessive stack allocation will be able to do so but not using
a single option.  Instead, they will need to use all three.

Martin

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-11 17:56         ` Martin Sebor
@ 2016-07-15 17:05           ` Aldy Hernandez
  0 siblings, 0 replies; 26+ messages in thread
From: Aldy Hernandez @ 2016-07-15 17:05 UTC (permalink / raw)
  To: Martin Sebor, Manuel López-Ibáñez, gcc-patches,
	Martin Sebor, Jeff Law
  Cc: Andrew MacLeod

On 07/11/2016 01:56 PM, Martin Sebor wrote:
> On 07/11/2016 09:40 AM, Aldy Hernandez wrote:
>> On 07/11/2016 11:08 AM, Martin Sebor wrote:
>>>>
>>>> Hey, I'm all for different options.  It would definitely be easier for
>>>> me :).  I wast trying really hard to use -Wvla= and keep the current
>>>> -Wvla meaning the same.  Though I see your point about using -Wvla* but
>>>> using different variables for representing -Wvla and -Wvla=blah.
>>>>
>>>> The easiest thing would be:
>>>>
>>>> -Wvla: Current behavior (warn on everything).
>>>>
>>>> -Wvla-larger-than=xxxx: Warn on unbounded VLA and bounded VLAs > xxxx.
>>>>
>>>> -Walloca: Warn on every use of alloca (analogous to -Wvla).
>>>>
>>>> -Walloca-larger-than=xxxx: Warn on unbounded alloca and bounded allocas
>>>>  > xxxx.
>>>>
>>>> This seems straightforward and avoids all the overloading you see.
>>>> Would
>>>> this be ok with everyone?
>>>
>>> I like the consistency.
>>>
>>> Given the common root with -Wlarger-than=N, what do envision the effect
>>> of setting -Wlarger-than=N to be on the two new options?
>>>
>>> FWIW, I tend to view -Wlarger-than= and certainly -Wframe-larger-than=
>>> not warning on alloca larger than N as a defect.  It could be fixed by
>>> simply hooking -Walloca-larger-than= up to it.
>>
>> I'm not touching any of these independent options.  -Wvla-larger-than=
>> and -Walloca-larger-than= will be implemented independently of whatever
>> -Wlarger-than= and -Wframe-larger-than=.  Any problems with these last
>> two options can be treated indpendently (PRs).
>
> Strictly speaking there is no defect in -Wframe-larger-than= because
> it's documented not to warn for alloca or VLAs.  I asked because it
> seems like an unnecessary (and IMO undesirable) limitation that could
> be easily removed as part of this patch.  Not removing it, OTOH, and
> providing a separate solution, feels like highlighting the limitation.
> With the new options, users interested in detecting all forms of
> excessive stack allocation will be able to do so but not using
> a single option.  Instead, they will need to use all three.

I'll address this as a follow-up patch.

Aldy

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-10 22:09 ` Martin Sebor
  2016-07-11 14:32   ` Jeff Law
@ 2016-07-15 17:05   ` Aldy Hernandez
  2016-07-16 21:08     ` Martin Sebor
  2016-07-17 15:53     ` Manuel López-Ibáñez
  1 sibling, 2 replies; 26+ messages in thread
From: Aldy Hernandez @ 2016-07-15 17:05 UTC (permalink / raw)
  To: Martin Sebor, gcc-patches, Martin Sebor, Jeff Law; +Cc: Andrew MacLeod

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

On 07/10/2016 06:09 PM, Martin Sebor wrote:
> On 07/08/2016 05:48 AM, Aldy Hernandez wrote:
>> [New thread now that I actually have a tested patch :)].
> ...
>> I have overhauled the options and added extensive documentation to
>> invoke.texi explaining them.  See the included testcases.  I have tried
>> to add a testcase for everything the pass currently handles.
>>
>> In the interest of keeping a consistent relationship with -Wvla, we now
>> have:
>>
>> -Walloca:    Warn on every use of alloca (not VLAs).
>> -Walloca=999:    Warn on unbounded uses of alloca, bounded uses with
>>          no known limit, and bounded uses where the number of
>>          bytes is greater than 999.
>> -Wvla:        Behaves as currently (warn on every use of VLAs).
>> -Wvla=999:    Similar to -Walloca=999, but for -Wvla.
>>
>> Notice plain -Walloca doesn't have a default, and just warns on every
>> use of alloca, just like -Wvla does for VLAs.  This way we can be
>> consistent with -Wvla, and just add the -Wvla=999 variant.
>
> I like it!
>
>> This patch depends on range information, which is less than stellar past
>> the VRP pass.  To get better range information, we'd have to incorporate
>> this somehow into the VRP pass and use the ASSERT_EXPRs therein.  And
>> still, VRP gets awfully confused with PHI merge points.  Andrew Macleod
>> is working on a new fancy range info infrastructure that should
>> eliminate a lot of the false positives we may get and/or help us
>> diagnose a wider range of cases.  Hence the reason that I'm not bending
>> over backwards to incorporate this pass into tree-vrp.c.
>>
>> FYI, I have a few XFAILed tests in this patch, to make sure we don't
>> lose track of possible improvements (which in this case should be
>> handled by better range info).  What's the blessed way of doing this?
>> Are adding new XFAILed tests acceptable?
>>
>> I have regstrapped this patch on x86-64 Linux, and have tested the
>> resulting compiler by building glibc with:
>>
>> /source/glibc/configure --prefix=/usr CC="/path/bin/gcc -Walloca=5000"
>> --disable-werror
>>
>> This of course, pointed out all sorts of interesting things!
>>
>> Fire away!
>
> I've played with the patch a bit over the weekend and have a few
> comments and suggestions (I hope you won't regret encouraging me :)

Not at all.  Your feedback is quite valuable.

> I like the consistency between -Walloca and -Wvla! (And despite
> the volume of my remaining comments, the rest of the patch too!

Well, after Manuel's comments I decided to split things up as previously 
discussed:

-Wvla: warn on any VLA uses (as currently on mainline).
-Wvla-larger-than=N: warn on unbounded use of VLAs, etc.
-Walloca: same as -Wvla but for alloca.
-Walloca-larger-than=N: same as -Wvla-larger-than=N but for alloca.

>
> 1) Optimization.  Without -O2 GCC prints:
>
>    sorry, unimplemented: -Walloca ignored without -O2

Changed to only sorry() on the -Wvla-larger-than=* and 
-Walloca-larger-than=* options.  The -Wvla and -Walloca warnings work 
without optimization as you suggest below.

>
> It seems that a warning would be more appropriate here than
> a hard error, but the checker could, and I would say should, be
> made available (in a limited form) without optimization because
>   -Walloca with no argument doesn't rely on it.  I suspect in this
> form, -Walloca is probably mainly going to be useful as a mechanism
> to enforce a "thou shall not use alloca" policy, though not much
> more beyond that.  Some development processes only require that
> code build without optimization in order to allow a commit and
> do more extensive testing with optimization during continuous
> integration, and not enabling it at -O0 would make it difficult
> to adopt the warning on projects that use such a process.

Done.  -Walloca and -Wvla warn on any use of alloca and VLAs 
accordingly, with or without optimization.  I sorry() on the bounded cases.

>
> 2) When passed an argument of a signed type, GCC prints
>
>    warning: cast from signed type in alloca
>
> even though there is no explicit cast in the code.  It may not
> be obvious why the conversion is a problem in this context.  I
> would suggest to rephrase the warning along the lines of
> -Wsign-conversion which prints:
>
>    conversion to ‘long unsigned int’ from ‘int’ may change the sign of
> the result
>
> and add why it's a potential problem.  Perhaps something like:
>
>    argument to alloca may be too large due to conversion from
>    'int to 'long unsigned int'

Fixed:

void
g2 (short int n)
{
   void *p;
   p = __builtin_alloca (n);
   f (p);
}

b.c:9:5: warning: argument to alloca may be too large due to conversion 
from 'short int' to 'long unsigned int' [-Walloca-larger-than=]
    p = __builtin_alloca (n);
    ~~^~~~~~~~~~~~~~~~~~~~~~

I wonder whether we could do all this in the front-ends as in 
-Wsign-conversion, but this is something that can be done as a follow-up 
if we really want it.

>
> (In addition, assuming one accepts the lack of range checking and
> constant propagation, this aspect of -Walloca also doesn't need
> optimization.)

I did not do this.  It is technically possible, but I did not want to 
complicate things further.  -Walloca works without optimization, and 
flags everything.  -Walloca-larger-than=* works with -O2 and above.

>
> 3) I wonder if the warning should also detect alloca calls with
> a zero argument and VLAs of zero size.  They are both likely to
> be programmer errors.  (Although it seems that that would need
> to be done earlier than in the alloca pass.)

Fixed and test added as well.

>
> 4) I wasn't able to trigger the -Wvla=N warning with VLAs used
> in loops even though VRP provides the range of the value:
>
>    $ cat t.c && /build/gcc-walloca/gcc/xgcc -B /build/gcc-walloca/gcc
> -O2 -S -Wall -Wextra -Wpedantic -Wvla=3 -fdump-tree-vrp=/dev/stdout t.c
> | grep _2
>    void f0 (void*);
>
>    void f1 (void)
>    {
>      for (int i = 0; i != 32; ++i)
>      {
>        char a [i];
>        f0 (a);
>      }
>    }
>
>    _2: [0, 31]
>      sizetype _2;
>      _2 = (sizetype) i_16;
>      a.1_8 = __builtin_alloca_with_align (_2, 8);

There is a "documented" reason for this: :)

       // Do not warn on VLAs occurring in a loop, since VLAs are
       // guaranteed to be cleaned up when they go out of scope.
       // That is, there is a corresponding __builtin_stack_restore
       // at the end of the scope in which the VLA occurs.

>
> 5) The -Wvla=N logic only seems to take into consideration the number
> of elements but not the size of the element type. For example, I wasn't
> able to get it to warn on the following with -Wvla=255 or greater:
>
>    void f0 (void*);
>
>    void f1 (unsigned char a)
>    {
>      int x [a];   // or even char a [n][__INT_MAX__];
>      f0 (x);
>    }

That was a huge oversight (or should I say over-engineering) on my part. 
  Fixed.

>
> 6) The patch seems to assume that __builtin_alloca_with_align implies
> a VLA, but that need not be the case.  Based on tree dumps it looks
> like there is a way to distinguish a VLA from a call to the built-in.
> For accuracy's sake I think it would be worth making that distinction
> in the diagnostic.

Good catch.  Fixed:

-Walloca* only applies to alloca(), __builtin_alloca, and 
__builtin_alloca_with_align() called directly.  Whereas, 
__builtin_alloca_with_align() called through a VLA is warned as such. 
There is no wording distinction between direct calls to __builtin_alloca 
and direct calls to __builtin_alloca_with_align though, FYI.

>
> 7) The -Walloca=N and -Wvla=N argument is a 32-bit integer and no
> checking appears to be done to make sure it doesn't overflow, so
> that invoking GCC with an argument of UINT_MAX results in:
>
>    cc1: note: -Wvla=0 disables -Wvla.  Use -Wno-vla instead.
>
> and with larger arguments in imposing a limit that's modulo UINT_MAX.
> Although stack size in excess of UINT_MAX bytes is unlikely, it seems
> that such exceedingly large arguments should be handled more gracefully
> (if they cannot be stored in a size_t argument it would be nice give
> a warning).

This seems to be a limitation of the option handling machinery.  For 
example, by the time type I get a hold of the passed value in 
c_common_handle_option(), we don't even know there was an overflow.

That is, when you pass -Walloca-larger-than=4294967296 (MAX_UINT + 1), 
c_common_handle_option() just sees value == 0.  However, passing 
MAX_UINT is handled prior to c_common_handle_option in the generic 
machinery:

./cc1 a.c -fdump-tree-all-vops-alias-details-graph -quiet 
-Walloca-larger-than=4294967295 -O2

cc1: error: argument to ‘-Walloca-larger-than=’ should be a non-negative 
integer

This is a problem with the generic machinery so I would prefer someone 
file a bugzilla report :), as this affects other options.

For that matter, "type" in c_common_handle_option() seems to be of 
"signed int", whereas the option was defined in c.opt as UInteger.  That 
should probably be addressed as well.

Good catch, though.

>
> 8) Finally, I think it would be helpful to provide information about
> the values GCC used to decide to issue the warning, especially when
> optimization is involved.  In many cases it will not be immediately
> obvious how GCC determined that an alloca argument is too big, or
> what the limit even is (for instance, when the -Walloca=N option
> is set via a #pragma GCC diagnostic far away from the call).
> Mentioning both the argument value or range and the threshold for
> the warning will help make it clear.

Ughhh...you're making me write user friendly stuff.  The reason I got 
into compilers was so I wouldn't have to deal with the user :).

   if (n < 2000)
     {
     p = __builtin_alloca (n);
     f (p);
     }

./cc1 a.c -fdump-tree-all-vops-alias-details-graph -quiet -I/tmp 
-Walloca-larger-than=100 -O2
a.c: In function ‘g2’:
a.c:9:7: warning: argument to alloca may be too large 
[-Walloca-larger-than=]
      p = __builtin_alloca (n);
      ~~^~~~~~~~~~~~~~~~~~~~~~
a.c:9:7: note: limit is '100' bytes, but argument may be '1999'

Happy? :-)

Of course, the non-obvious cases may get ranges you may not expect. 
This should get better with improved range info.

>
> Martin
>
> PS I also ran into a couple internal compiler errors with the test
> cases below:
>
>    void f0 (void*);
>
>    void f1 (int a, int b)
>    {
>      int x [a][b];
>      f0 (x);
>    }

Fixed.  There were issues with multi-dimensional VLAs, but mainly it was 
me being overly smart with VLA inner types.

>
>    0x11def63 tree_to_uhwi(tree_node const*)
>    /src/gcc/walloca/gcc/tree.c:7339
>    ...
>
>    void f0 (void*);
>
>    void f1 (unsigned char a)
>    {
>      void *p = __builtin_alloca_with_align (a, 8);
>      f0 (p);
>    }

Fixed now that the distinction between direct 
__builtin_alloca_with_align calls and VLAs has been addressed.

Phew.  I think that's it.

Tested on x86-64 Linux.

What do you think?

Aldy

[-- Attachment #2: curr --]
[-- Type: text/plain, Size: 33521 bytes --]

gcc/

	* Makefile.in (OBJS): Add gimple-ssa-warn-walloca.o.
	* passes.def: Add two instances of pass_walloca.
	* tree-pass.h (make_pass_walloca): New.
	* gimple-ssa-warn-walloca.c: New file.
	* opts.c (finish_options): Warn when using -Wvla-larger-than= and
	-Walloca-larger-than= without -O2 or greater.
	* doc/invoke.texi: Document -Walloca, -Walloca-larger-than=, and
	-Wvla-larger-than= options.

gcc/c-family/

	* c.opt (Walloca): New.
	(Walloca-larger-than=): New.
	(Wvla-larger-than=): New.

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 776f6d7..2a13b8f 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1284,6 +1284,7 @@ OBJS = \
 	gimple-ssa-nonnull-compare.o \
 	gimple-ssa-split-paths.o \
 	gimple-ssa-strength-reduction.o \
+	gimple-ssa-warn-alloca.o \
 	gimple-streamer-in.o \
 	gimple-streamer-out.o \
 	gimple-walk.o \
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index ff6339c..dc2be2d 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -376,6 +376,16 @@ c_common_handle_option (size_t scode, const char *arg, int value,
       cpp_opts->warn_num_sign_change = value;
       break;
 
+    case OPT_Walloca_larger_than_:
+      if (!value)
+	inform (loc, "-Walloca-larger-than=0 is meaningless");
+      break;
+
+    case OPT_Wvla_larger_than_:
+      if (!value)
+	inform (loc, "-Wvla-larger-than=0 is meaningless");
+      break;
+
     case OPT_Wunknown_pragmas:
       /* Set to greater than 1, so that even unknown pragmas in
 	 system headers will be warned about.  */
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 83fd84c..a8e9532 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -275,6 +275,15 @@ Wall
 C ObjC C++ ObjC++ Warning
 Enable most warning messages.
 
+Walloca
+C ObjC C++ ObjC++ Var(warn_alloca) Warning
+
+Walloca-larger-than=
+C ObjC C++ ObjC++ Var(warn_alloca_limit) Warning Joined RejectNegative UInteger
+-Walloca-larger-than=<number> Warn on unbounded uses of
+alloca, and on bounded uses of alloca whose bound can be larger than
+<number> bytes.
+
 Warray-bounds
 LangEnabledBy(C ObjC C++ ObjC++,Wall)
 ; in common.opt
@@ -980,6 +989,12 @@ Wvla
 C ObjC C++ ObjC++ Var(warn_vla) Init(-1) Warning
 Warn if a variable length array is used.
 
+Wvla-larger-than=
+C ObjC C++ ObjC++ Var(warn_vla_limit) Warning Joined RejectNegative UInteger
+-Wvla-larger-than=<number> Warn on unbounded uses of variable-length arrays, and
+on bounded uses of variable-length arrays whose bound can be
+larger than <number> bytes.
+
 Wvolatile-register-var
 C ObjC C++ ObjC++ Var(warn_volatile_register_var) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
 Warn when a register variable is declared volatile.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 2105351..98a4a5b 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -253,6 +253,7 @@ Objective-C and Objective-C++ Dialects}.
 @gccoptlist{-fsyntax-only  -fmax-errors=@var{n}  -Wpedantic @gol
 -pedantic-errors @gol
 -w  -Wextra  -Wall  -Waddress  -Waggregate-return  @gol
+-Walloca -Walloca-larger-than=@var{n} @gol
 -Wno-aggressive-loop-optimizations -Warray-bounds -Warray-bounds=@var{n} @gol
 -Wno-attributes -Wbool-compare -Wno-builtin-macro-redefined @gol
 -Wc90-c99-compat -Wc99-c11-compat @gol
@@ -309,7 +310,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wunused-const-variable -Wunused-const-variable=@var{n} @gol
 -Wunused-but-set-parameter -Wunused-but-set-variable @gol
 -Wuseless-cast -Wvariadic-macros -Wvector-operation-performance @gol
--Wvla -Wvolatile-register-var  -Wwrite-strings @gol
+-Wvla -Wvla-larger-than=@var{n} -Wvolatile-register-var  -Wwrite-strings @gol
 -Wzero-as-null-pointer-constant -Whsa}
 
 @item C and Objective-C-only Warning Options
@@ -4618,6 +4619,61 @@ annotations.
 Warn about overriding virtual functions that are not marked with the override
 keyword.
 
+@item -Walloca
+@opindex Wno-alloca
+@opindex Walloca
+This option warns on all uses of @code{alloca} in the source.
+
+@item -Walloca-larger-than=@var{n}
+This option warns on calls to @code{alloca} that are not bounded by a
+controlling predicate limiting its size to @var{n} bytes, or calls to
+@code{alloca} where the bound is unknown.
+
+For example, a bounded case of @code{alloca} could be:
+
+@smallexample
+unsigned int n;
+...
+if (n <= 1000)
+  alloca (n);
+@end smallexample
+
+In the above example, passing @code{-Walloca=1000} would not issue a
+warning because the call to @code{alloca} is known to be at most 1000
+bytes.  However, if @code{-Walloca=500} was passed, the compiler would
+have emitted a warning.
+
+Unbounded uses, on the other hand, are uses of @code{alloca} with no
+controlling predicate verifying its size.  For example:
+
+@smallexample
+stuff ();
+alloca (n);
+@end smallexample
+
+If @code{-Walloca=500} was passed, the above would trigger a warning,
+but this time because of the lack of bounds checking.
+
+Note, that even seemingly correct code involving signed integers could
+cause a warning:
+
+@smallexample
+signed int n;
+...
+if (n < 500)
+  alloca (n);
+@end smallexample
+
+In the above example, @var{n} could be negative, causing a larger than
+expected argument to be implicitly casted into the @code{alloca} call.
+
+This option also warns when @code{alloca} is used in a loop.
+
+This warning is not enabled by @option{-Wall}, and is only active when
+@option{-ftree-vrp} is active (default for @option{-O2} and above).
+
+See also @option{-Wvla-larger-than=@var{n}}.
+
 @item -Warray-bounds
 @itemx -Warray-bounds=@var{n}
 @opindex Wno-array-bounds
@@ -5782,9 +5838,21 @@ moving from a moved-from object, this warning can be disabled.
 @item -Wvla
 @opindex Wvla
 @opindex Wno-vla
-Warn if variable length array is used in the code.
+Warn if a variable-length array is used in the code.
 @option{-Wno-vla} prevents the @option{-Wpedantic} warning of
-the variable length array.
+the variable-length array.
+
+@item -Wvla-larger-than=@var{n}
+If this option is used, the compiler will warn on uses of
+variable-length arrays where the size is either unbounded, or bounded
+by an argument that can be larger than @var{n} bytes.  This is similar
+to how @option{-Walloca-larger-than=@var{n}} works, but with
+variable-length arrays.
+
+This warning is not enabled by @option{-Wall}, and is only active when
+@option{-ftree-vrp} is active (default for @option{-O2} and above).
+
+See also @option{-Walloca-larger-than=@var{n}}.
 
 @item -Wvolatile-register-var
 @opindex Wvolatile-register-var
diff --git a/gcc/gimple-ssa-warn-alloca.c b/gcc/gimple-ssa-warn-alloca.c
new file mode 100644
index 0000000..cbd6535
--- /dev/null
+++ b/gcc/gimple-ssa-warn-alloca.c
@@ -0,0 +1,486 @@
+/* Warn on problematic uses of alloca and variable length arrays.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Contributed by Aldy Hernandez <aldyh@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+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/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "ssa.h"
+#include "gimple-pretty-print.h"
+#include "diagnostic-core.h"
+#include "fold-const.h"
+#include "gimple-iterator.h"
+#include "tree-ssa.h"
+#include "params.h"
+#include "tree-cfg.h"
+#include "calls.h"
+#include "cfgloop.h"
+
+const pass_data pass_data_walloca = {
+  GIMPLE_PASS,
+  "walloca",
+  OPTGROUP_NONE,
+  TV_NONE,
+  PROP_cfg, // properties_required
+  0,	    // properties_provided
+  0,	    // properties_destroyed
+  0,	    // properties_start
+  0,	    // properties_finish
+};
+
+class pass_walloca : public gimple_opt_pass
+{
+public:
+  pass_walloca (gcc::context *ctxt)
+    : gimple_opt_pass(pass_data_walloca, ctxt), first_time_p (false)
+  {}
+  opt_pass *clone () { return new pass_walloca (m_ctxt); }
+  void set_pass_param (unsigned int n, bool param)
+    {
+      gcc_assert (n == 0);
+      first_time_p = param;
+    }
+  virtual bool gate (function *);
+  virtual unsigned int execute (function *);
+
+ private:
+  // Set to TRUE the first time we run this pass on a function.
+  bool first_time_p;
+};
+
+bool
+pass_walloca::gate (function *fun ATTRIBUTE_UNUSED)
+{
+  // The first time this pass is called, it is called before
+  // optimizations have been run and range information is unavailable,
+  // so we can only perform strict alloca checking.
+  if (first_time_p)
+    return warn_alloca != 0;
+
+  return warn_alloca_limit > 0 || warn_vla_limit > 0;
+}
+
+// Possible problematic uses of alloca.
+enum alloca_type {
+  // Alloca argument is within known bounds that are appropriate.
+  ALLOCA_OK,
+
+  // Alloca argument is KNOWN to have a value that is too large.
+  ALLOCA_BOUND_DEFINITELY_LARGE,
+
+  // Alloca argument may be too large.
+  ALLOCA_BOUND_MAYBE_LARGE,
+
+  // Alloca argument is bounded but of an indeterminate size.
+  ALLOCA_BOUND_UNKNOWN,
+
+  // Alloca argument was casted from a signed integer.
+  ALLOCA_CAST_FROM_SIGNED,
+
+  // Alloca appears in a loop.
+  ALLOCA_IN_LOOP,
+
+  // Alloca argument is 0.
+  ALLOCA_ARG_IS_ZERO,
+
+  // Alloca call is unbounded.  That is, there is no controlling
+  // predicate for its argument.
+  ALLOCA_UNBOUNDED
+};
+
+// We have a few heuristics up our sleeve to determine if a call to
+// alloca() is within bounds.  Try them out and return the type of
+// alloca call this is based on its argument.
+//
+// Given a known argument (ARG) to alloca() and an EDGE (E)
+// calculating said argument, verify that the last statement in the BB
+// in E->SRC is a gate comparing ARG to an acceptable bound for
+// alloca().  See examples below.
+//
+// MAX_SIZE is WARN_ALLOCA= adjusted for VLAs.  It is the maximum size
+// in bytes we allow for arg.
+//
+// If the alloca bound is determined to be too large, ASSUMED_LIMIT is
+// set to the bound used to determine this.  ASSUMED_LIMIT is only set
+// for ALLOCA_BOUND_MAYBE_LARGE and ALLOCA_BOUND_DEFINITELY_LARGE.
+//
+// Returns the alloca type.
+
+static enum alloca_type
+alloca_call_type_by_arg (tree arg, edge e, unsigned max_size,
+			 wide_int *assumed_limit)
+{
+  // All the tests bellow depend on the jump being on the TRUE path.
+  if (!(e->flags & EDGE_TRUE_VALUE))
+    return ALLOCA_UNBOUNDED;
+
+  basic_block bb = e->src;
+  gimple_stmt_iterator gsi = gsi_last_bb (bb);
+  gimple *last = gsi_stmt (gsi);
+  if (!last || gimple_code (last) != GIMPLE_COND)
+    return ALLOCA_UNBOUNDED;
+
+  /* Check for:
+     if (ARG <= N)
+       goto <bb 3>;
+      else
+        goto <bb 4>;
+      <bb 3>:
+      alloca(ARG);
+  */
+  if (gimple_cond_code (last) == LE_EXPR
+      && gimple_cond_lhs (last) == arg)
+    {
+      if (TREE_CODE (gimple_cond_rhs (last)) == INTEGER_CST)
+	{
+	  tree rhs = gimple_cond_rhs (last);
+	  if (tree_to_uhwi (rhs) > max_size)
+	    {
+	      *assumed_limit = rhs;
+	      return ALLOCA_BOUND_MAYBE_LARGE;
+	    }
+	  return ALLOCA_OK;
+	}
+      else
+	return ALLOCA_BOUND_UNKNOWN;
+    }
+
+  /* Check for:
+     if (arg .cond. LIMIT) -or- if (LIMIT .cond. arg)
+       alloca(arg);
+
+     Where LIMIT has a bound of unknown range.  */
+  tree limit = NULL;
+  if (gimple_cond_lhs (last) == arg)
+    limit = gimple_cond_rhs (last);
+  else if (gimple_cond_rhs (last) == arg)
+    limit = gimple_cond_lhs (last);
+  if (limit && TREE_CODE (limit) == SSA_NAME)
+    {
+      wide_int min, max;
+      value_range_type range_type = get_range_info (limit, &min, &max);
+      if (range_type == VR_UNDEFINED || range_type == VR_VARYING)
+	return ALLOCA_BOUND_UNKNOWN;
+      // FIXME: We could try harder here and handle a possible range
+      // or anti-range.  Hopefully the upcoming changes to range info
+      // will give us finer grained info, and we can avoid somersaults
+      // here.
+    }
+
+  return ALLOCA_UNBOUNDED;
+}
+
+// Return TRUE if SSA's definition is a cast from a signed type.
+// If so, set *INVALID_CASTED_TYPE to the signed type.
+
+static bool
+cast_from_signed_p (tree ssa, tree *invalid_casted_type)
+{
+  gimple *def = SSA_NAME_DEF_STMT (ssa);
+  if (def
+      && !gimple_nop_p (def)
+      && gimple_assign_cast_p (def)
+      && !TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (def))))
+    {
+      *invalid_casted_type = TREE_TYPE (gimple_assign_rhs1 (def));
+      return true;
+    }
+  return false;
+}
+
+// Return TURE if X has a maximum range of MAX, basically covering the
+// entire domain, in which case it's no range at all.
+
+static bool
+is_max (tree x, wide_int max)
+{
+  return wi::max_value (TREE_TYPE (x)) == max;
+}
+
+// Analyze the alloca call in STMT and return an `enum alloca_type'
+// explaining what type of alloca it is.  IS_VLA is set if the alloca
+// call is really a BUILT_IN_ALLOCA_WITH_ALIGN, signifying a VLA.
+//
+// If the alloca bound is determined to be too large, ASSUMED_LIMIT is
+// set to the bound used to determine this.  ASSUMED_LIMIT is only set
+// for ALLOCA_BOUND_MAYBE_LARGE and ALLOCA_BOUND_DEFINITELY_LARGE.
+//
+// If the alloca call may be too large because of a cast from a signed
+// type to an unsigned type, set *INVALID_CASTED_TYPE to the
+// problematic signed type.
+
+static enum alloca_type
+alloca_call_type (gimple *stmt, bool is_vla, wide_int *assumed_limit,
+		  tree *invalid_casted_type)
+{
+  gcc_assert (gimple_alloca_call_p (stmt));
+  tree len = gimple_call_arg (stmt, 0);
+  enum alloca_type w = ALLOCA_UNBOUNDED;
+  wide_int min, max;
+
+  if (is_vla)
+    gcc_assert (warn_vla_limit > 0);
+  if (!is_vla)
+    gcc_assert (warn_alloca_limit > 0);
+
+  // Check if we're in a loop.
+  basic_block bb = gimple_bb (stmt);
+  if (bb->loop_father
+      // ?? Functions with no loops get a loop_father?  I
+      // don't get it.  The following conditional seems to do
+      // the trick to exclude such nonsense.
+      && bb->loop_father->header != ENTRY_BLOCK_PTR_FOR_FN (cfun))
+    {
+      // Do not warn on VLAs occurring in a loop, since VLAs are
+      // guaranteed to be cleaned up when they go out of scope.
+      // That is, there is a corresponding __builtin_stack_restore
+      // at the end of the scope in which the VLA occurs.
+      tree fndecl = gimple_call_fn (stmt);
+      while (TREE_CODE (fndecl) == ADDR_EXPR)
+	fndecl = TREE_OPERAND (fndecl, 0);
+      if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+	  && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA_WITH_ALIGN)
+	return ALLOCA_OK;
+
+      return ALLOCA_IN_LOOP;
+    }
+
+  // Adjust warn_alloca_max_size for VLAs, by taking the underlying
+  // type into account.
+  unsigned HOST_WIDE_INT max_size;
+  if (is_vla)
+    max_size = (unsigned HOST_WIDE_INT) warn_vla_limit;
+  else
+    max_size = (unsigned HOST_WIDE_INT) warn_alloca_limit;
+
+  // Check for the obviously bounded case.
+  if (TREE_CODE (len) == INTEGER_CST)
+    {
+      if (tree_to_uhwi (len) > max_size)
+	{
+	  *assumed_limit = len;
+	  return ALLOCA_BOUND_DEFINITELY_LARGE;
+	}
+      if (integer_zerop (len))
+	return ALLOCA_ARG_IS_ZERO;
+      w = ALLOCA_OK;
+    }
+  else if (TREE_CODE (len) != SSA_NAME)
+    return ALLOCA_UNBOUNDED;
+  // Check the range info if available.
+  else
+    {
+      if (value_range_type range_type = get_range_info (len, &min, &max))
+	{
+	  if (range_type == VR_RANGE)
+	    {
+	      if (wi::leu_p (max, max_size))
+		w = ALLOCA_OK;
+	      else if (is_max (len, max))
+		{
+		  // A cast may have created a range we don't care
+		  // about.  For instance, a cast from 16-bit to
+		  // 32-bit creates a range of 0..65535, even if there
+		  // is not really a determinable range in the
+		  // underlying code.  In this case, look through the
+		  // cast at the original argument, and fall through
+		  // to look at other alternatives.
+		  gimple *def = SSA_NAME_DEF_STMT (len);
+		  if (gimple_assign_cast_p (def))
+		    len = gimple_assign_rhs1 (def);
+		}
+	      else
+		{
+		  /* If `len' is merely a cast that is being
+		     calculated right before the call to alloca, look
+		     at the range for the original value.
+
+		     This avoids the cast creating a range where the
+		     original expression did not have a range:
+
+		     # RANGE [0, 18446744073709551615] NONZERO 4294967295
+		     _2 = (long unsigned int) n_7(D);
+		     p_9 = __builtin_alloca (_2);
+
+		     The correct thing would've been for the user to
+		     use size_t, which in the case above would've been
+		     'long unsigned int', and everything would've
+		     worked.  But we have to catch cases where the
+		     user is using some other compatible type for the
+		     call argument to alloca (say unsigned short).  */
+		  gimple *def = SSA_NAME_DEF_STMT (len);
+		  if (gimple_assign_cast_p (def))
+		    {
+		      len = gimple_assign_rhs1 (def);
+		      range_type = get_range_info (len, &min, &max);
+		    }
+
+		  if (range_type != VR_VARYING && is_max (len, max))
+		    {
+		      // Treat a max of the entire domain as if it had no
+		      // range info, and fall through the try other
+		      // alternatives.
+		    }
+		  else
+		    {
+		      *assumed_limit = max;
+		      return ALLOCA_BOUND_MAYBE_LARGE;
+		    }
+		}
+	    }
+	  else if (range_type == VR_ANTI_RANGE)
+	    {
+	      // There may be some wrapping around going on.  Catch it
+	      // with this heuristic.  Hopefully, this VR_ANTI_RANGE
+	      // nonsense will go away, and we won't have to catch the
+	      // sign conversion problems with this crap.
+	      if (cast_from_signed_p (len, invalid_casted_type))
+		return ALLOCA_CAST_FROM_SIGNED;
+
+	      // Fall thru and try other things.
+	    }
+	  else if (range_type == VR_VARYING)
+	    {
+	      // No easily determined range.  Try other things.
+	    }
+	}
+    }
+
+  // If we couldn't find anything, try a few heuristics for things we
+  // can easily determine.  Check these misc cases but only accept
+  // them if all predecessors have a known bound.
+  if (w == ALLOCA_UNBOUNDED)
+    {
+      w = ALLOCA_OK;
+      for (unsigned ix = 0; ix < EDGE_COUNT (bb->preds); ix++)
+	{
+	  enum alloca_type w
+	    = alloca_call_type_by_arg (len, EDGE_PRED (bb, ix), max_size,
+				       assumed_limit);
+	  if (w != ALLOCA_OK)
+	    return w;
+	}
+    }
+
+  return w;
+}
+
+unsigned int
+pass_walloca::execute (function *fun)
+{
+  basic_block bb;
+  FOR_EACH_BB_FN (bb, fun)
+    {
+      for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);
+	   gsi_next (&si))
+	{
+	  gimple *stmt = gsi_stmt (si);
+	  location_t loc = gimple_location (stmt);
+
+	  if (!gimple_alloca_call_p (stmt))
+	    continue;
+	  gcc_assert (gimple_call_num_args (stmt) >= 1);
+
+	  bool is_vla = gimple_alloca_call_p (stmt)
+	    && gimple_call_alloca_for_var_p (as_a <gcall *> (stmt));
+
+	  // Strict mode whining for VLAs is handled by the front-end,
+	  // so we can safely ignore this case.  Also, ignore VLAs if
+	  // the user doesn't care about them.
+	  if (is_vla
+	      && (warn_vla > 0 || !warn_vla_limit))
+	    continue;
+
+	  if (!is_vla && (warn_alloca || !warn_alloca_limit))
+	    {
+	      if (warn_alloca)
+		warning_at (loc, OPT_Walloca, "use of alloca");
+	      continue;
+	    }
+
+	  wide_int assumed_limit
+	    = wi::to_wide (integer_zero_node,
+			   TYPE_PRECISION (size_type_node));
+	  tree invalid_casted_type = NULL;
+	  enum alloca_type w = alloca_call_type (stmt, is_vla, &assumed_limit,
+						 &invalid_casted_type);
+	  enum opt_code wcode
+	    = is_vla ? OPT_Wvla_larger_than_ : OPT_Walloca_larger_than_;
+	  const char *alloca_str
+	    = is_vla ? "variable-length array" : "alloca";
+	  char buff[WIDE_INT_MAX_PRECISION / 4 + 4];
+	  switch (w)
+	    {
+	    case ALLOCA_OK:
+	      break;
+	    case ALLOCA_BOUND_MAYBE_LARGE:
+	      gcc_assert (assumed_limit != 0);
+	      if (warning_at (loc, wcode,
+			      "argument to %s may be too large", alloca_str))
+		{
+		  print_decu (assumed_limit, buff);
+		  inform (loc, "limit is '%u' bytes, but argument may be '%s'",
+			  is_vla ? warn_vla_limit : warn_alloca_limit, buff);
+		}
+	      break;
+	    case ALLOCA_BOUND_DEFINITELY_LARGE:
+	      gcc_assert (assumed_limit != 0);
+	      if (warning_at (loc, wcode,
+			      "argument to %s is too large", alloca_str))
+		{
+		  print_decu (assumed_limit, buff);
+		  inform (loc, "limit is %u' bytes, but argument is '%s'",
+			  is_vla ? warn_vla_limit : warn_alloca_limit, buff);
+		}
+	      break;
+	    case ALLOCA_BOUND_UNKNOWN:
+	      warning_at (loc, wcode, "%s bound is unknown", alloca_str);
+	      break;
+	    case ALLOCA_UNBOUNDED:
+	      warning_at (loc, wcode, "unbounded use of %s", alloca_str);
+	      break;
+	    case ALLOCA_IN_LOOP:
+	      warning_at (loc, wcode, "use of %s within a loop", alloca_str);
+	      break;
+	    case ALLOCA_CAST_FROM_SIGNED:
+	      gcc_assert (invalid_casted_type != NULL_TREE);
+	      warning_at (loc, wcode, "argument to %s may be too large due to "
+			  "conversion from '%T' to '%T'",
+			  alloca_str, invalid_casted_type, size_type_node);
+	      break;
+	    case ALLOCA_ARG_IS_ZERO:
+	      warning_at (loc, wcode, "argument to %s is zero", alloca_str);
+	      break;
+	    default:
+	      gcc_unreachable ();
+	    }
+	}
+    }
+  return 0;
+}
+
+gimple_opt_pass *
+make_pass_walloca (gcc::context *ctxt)
+{
+  return new pass_walloca (ctxt);
+}
diff --git a/gcc/opts.c b/gcc/opts.c
index e80331f..8a84901 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -743,6 +743,20 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
   if (opts->x_flag_tm && opts->x_flag_non_call_exceptions)
     sorry ("transactional memory is not supported with non-call exceptions");
 
+  // -Walloca-larger-than=N needs range info which is only available at -O2.
+  if (opts->x_warn_alloca_limit > 0 && opts->x_optimize < 2)
+    {
+      sorry ("-Walloca-larger-than=N ignored without -O2");
+      opts->x_warn_alloca_limit = 0;
+    }
+
+  // -Wvla-larger-than= needs range info which is only available at -O2.
+  if (opts->x_warn_vla_limit > 0 && opts->x_optimize < 2)
+    {
+      sorry ("-Wvla-larger-than= ignored without -O2");
+      opts->x_warn_vla_limit = 0;
+    }
+
   /* Unless the user has asked for section anchors, we disable toplevel
      reordering at -O0 to disable transformations that might be surprising
      to end users and to get -fno-toplevel-reorder tested.  */
diff --git a/gcc/passes.def b/gcc/passes.def
index 3647e90..591add2 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3.  If not see
   NEXT_PASS (pass_warn_function_return);
   NEXT_PASS (pass_expand_omp);
   NEXT_PASS (pass_build_cgraph_edges);
+  NEXT_PASS (pass_walloca, /*strict_mode_p=*/true);
   TERMINATE_PASS_LIST (all_lowering_passes)
 
   /* Interprocedural optimization passes.  */
@@ -303,6 +304,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_simduid_cleanup);
       NEXT_PASS (pass_lower_vector_ssa);
       NEXT_PASS (pass_cse_reciprocals);
+      NEXT_PASS (pass_walloca, /*strict_mode_p=*/false);
       NEXT_PASS (pass_reassoc, false /* insert_powi_p */);
       NEXT_PASS (pass_strength_reduction);
       NEXT_PASS (pass_split_paths);
diff --git a/gcc/testsuite/gcc.dg/Walloca-1.c b/gcc/testsuite/gcc.dg/Walloca-1.c
new file mode 100644
index 0000000..3cde6de
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-1.c
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=2000 -O2" } */
+
+#define alloca __builtin_alloca
+
+typedef __SIZE_TYPE__ size_t;
+extern size_t strlen(const char *);
+
+extern void useit (char *);
+
+int num;
+
+void foo1 (size_t len, size_t len2, size_t len3)
+{
+  int i;
+
+  for (i=0; i < 123; ++i)
+    {
+      char *s = alloca (566);	/* { dg-warning "alloca within a loop" } */
+      useit (s);
+    }
+
+  char *s = alloca (123);
+  useit (s);			// OK, constant argument to alloca
+
+  s = alloca (num);		// { dg-warning "large due to conversion" }
+  useit (s);
+
+  s = alloca(90000);		/* { dg-warning "is too large" } */
+  useit (s);
+
+  if (len < 2000)
+    {
+      s = alloca(len);		// OK, bounded
+      useit (s);
+    }
+
+  if (len + len2 < 2000)	// OK, bounded
+    {
+      s = alloca(len + len2);
+      useit (s);
+    }
+
+  if (len3 <= 2001)
+    {
+      s = alloca(len3);		/* { dg-warning "may be too large" } */
+      useit(s);
+    }
+}
+
+void foo2 (__SIZE_TYPE__ len)
+{
+  // Test that a direct call to __builtin_alloca_with_align is not confused
+  // with a VLA.
+  void *p = __builtin_alloca_with_align (len, 8); // { dg-warning "unbounded use of alloca" }
+  useit (p);
+}
+
+void foo3 (unsigned char a)
+{
+  if (a == 0)
+    useit (__builtin_alloca (a)); // { dg-warning "argument to alloca is zero" }
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-2.c b/gcc/testsuite/gcc.dg/Walloca-2.c
new file mode 100644
index 0000000..548e0ed
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-2.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=2000 -O2" } */
+
+void f (void *);
+
+void
+g1 (int n)
+{
+  void *p;
+  if (n > 0 && n < 2000)
+    p = __builtin_alloca (n);
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
+
+void
+g2 (int n)
+{
+  void *p;
+  if (n < 2000)
+    p = __builtin_alloca (n); // { dg-warning "large due to conversion" }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
+
+void
+g3 (int n)
+{
+  void *p;
+  if (n > 0 && n < 3000)
+    {
+      p = __builtin_alloca (n); // { dg-warning "alloca may be too large" }
+      // { dg-message "note:.*argument may be '2999'" "note" { target *-*-* } 34 }
+    }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-3.c b/gcc/testsuite/gcc.dg/Walloca-3.c
new file mode 100644
index 0000000..28df13c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-3.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=2000 -O2" } */
+
+void f (void *);
+
+__SIZE_TYPE__ LIMIT;
+
+// Warn when there is an alloca bound, but it is an unknown bound.
+
+void
+g1 (__SIZE_TYPE__ n)
+{
+  void *p;
+  if (n < LIMIT)
+    p = __builtin_alloca (n); // { dg-warning "alloca bound is unknown" }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
+
+// Similar to the above, but do not get confused by the upcast.
+
+unsigned short SHORT_LIMIT;
+void
+g2 (unsigned short n)
+{
+  void *p;
+  if (n < SHORT_LIMIT)
+    p = __builtin_alloca (n); // { dg-warning "alloca bound is unknown" }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-4.c b/gcc/testsuite/gcc.dg/Walloca-4.c
new file mode 100644
index 0000000..d96cc4e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-4.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=5000 -O2" } */
+/* { dg-xfail-if "Currently broken but Andrew's work should fix this" { *-*-* } } */
+
+// Should be another variant of Walloca-7.c.
+// This should not warn, as we have a known bound within limits.
+
+ char *
+ _i18n_number_rewrite (char *w, char *rear_ptr)
+{
+
+  char *src;
+ _Bool 
+      use_alloca = (((rear_ptr - w) * sizeof (char)) < 4096U);
+ if (use_alloca)
+    src = (char *) __builtin_alloca ((rear_ptr - w) * sizeof (char));
+  else
+    src = (char *) __builtin_malloc ((rear_ptr - w) * sizeof (char));
+  return src;
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-5.c b/gcc/testsuite/gcc.dg/Walloca-5.c
new file mode 100644
index 0000000..5ed1171
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-5.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=123 -O2" } */
+/* { dg-xfail-if "Currently broken but Andrew's work should fix this" { *-*-* } } */
+
+/* The argument to alloca ends up having a range of 0..MAXINT(32bits),
+   so we think we have a range because of the upcast.  Consequently,
+   we warn with "alloca may be too large", but we should technically
+   warn with "unbounded use of alloca".
+
+   We currently drill through casts to figure this stuff out, but we
+   get confused because it's not just a cast.  It's a cast, plus a
+   multiply.
+
+   <bb 2>:
+  # RANGE [0, 4294967295] NONZERO 4294967295
+  _1 = (long unsigned int) something_4(D);
+  # RANGE [0, 34359738360] NONZERO 34359738360
+  _2 = _1 * 8;
+  _3 = __builtin_alloca (_2);
+
+  I don't know whether it's even worth such fine-grained warnings.
+  Perhaps we should generically warn everywhere with "alloca may be
+  too large".
+
+  I'm hoping that this particular case will be easier to diagnose with
+  Andrew's work.  */
+
+void useit(void *);
+void foobar(unsigned int something)
+{
+  useit(__builtin_alloca (something * sizeof (const char *))); // { dg-warning "unbounded use of alloca" "" { xfail *-*-* } }
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-6.c b/gcc/testsuite/gcc.dg/Walloca-6.c
new file mode 100644
index 0000000..b4d8d41
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-6.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=256 -O2" } */
+/* { dg-xfail-if "Currently broken but Andrew's work should fix this" { *-*-* } } */
+
+void f (void*);
+void g (__SIZE_TYPE__ n)
+{
+  // No warning on this case.  Range is easily determinable.
+  if (n > 0 && n < 256)
+    f (__builtin_alloca (n));
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-7.c b/gcc/testsuite/gcc.dg/Walloca-7.c
new file mode 100644
index 0000000..8476aab
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-7.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca -O0" } */
+
+extern void f(void *);
+
+void foo(void)
+{
+  // Test that strict -Walloca works even without optimization.
+  f (__builtin_alloca(500)); // { dg-warning "use of alloca" }
+}
+
+void bar(void)
+{
+  // Test that we warn on alloca() calls, not just __builtin_alloca calls.
+  extern void *alloca(__SIZE_TYPE__);
+  f (alloca (123)); // { dg-warning "use of alloca" }
+}
diff --git a/gcc/testsuite/gcc.dg/Wvla-1.c b/gcc/testsuite/gcc.dg/Wvla-1.c
new file mode 100644
index 0000000..384c930
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wvla-1.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-Wvla-larger-than=100 -O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern void useit (char *);
+
+int num;
+
+void test_vlas (size_t num)
+{
+  char str2[num];		/* { dg-warning "unbounded use" } */
+  useit(str2);
+
+  num = 98;
+  for (int i=0; i < 1234; ++i) {
+    char str[num];	        // OK, VLA in a loop, but it is a
+				// known size *AND* the compiler takes
+				// care of cleaning up between
+				// iterations with
+				// __builtin_stack_restore.
+    useit(str);
+  }
+}
diff --git a/gcc/testsuite/gcc.dg/Wvla-2.c b/gcc/testsuite/gcc.dg/Wvla-2.c
new file mode 100644
index 0000000..1124f21
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wvla-2.c
@@ -0,0 +1,60 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target stdint_types } */
+/* { dg-options "-O2 -Wvla-larger-than=40" } */
+
+#include <stdint.h>
+
+void f0 (void *);
+void
+f1 (__SIZE_TYPE__ a)
+{
+  if (a <= 10)
+    {
+      // 10 * 4 bytes = 40: OK!
+      uint32_t x[a];
+      f0 (x);
+    }
+}
+
+void
+f2 (__SIZE_TYPE__ a)
+{
+  if (a <= 11)
+    {
+      // 11 * 4 bytes = 44: Not OK.
+      uint32_t x[a]; // { dg-warning "array may be too large" }
+      // { dg-message "note:.*argument may be '44'" "note" { target *-*-* } 25 }
+      f0 (x);
+    }
+}
+
+void
+f3 (__SIZE_TYPE__ a, __SIZE_TYPE__ b)
+{
+  if (a <= 5 && b <= 3)
+    {
+      // 5 * 3 * 4 bytes = 60: Not OK.
+      uint32_t x[a][b]; // { dg-warning "array may be too large" }
+      f0 (x);
+    }
+}
+
+void
+f4 (__SIZE_TYPE__ a, __SIZE_TYPE__ b)
+{
+  if (a <= 5 && b <= 2)
+    {
+      // 5 * 2 * 4 bytes = 40 bytes: OK!
+      uint32_t x[a][b];
+      f0 (x);
+    }
+}
+
+void
+f5 (__SIZE_TYPE__ len)
+{
+  // Test that a direct call to __builtin_alloca_with_align is not
+  // confused with a VLA.
+  void *p = __builtin_alloca_with_align (len, 8);
+  f0 (p);
+}
diff --git a/gcc/testsuite/gcc.dg/Wvla-3.c b/gcc/testsuite/gcc.dg/Wvla-3.c
new file mode 100644
index 0000000..5124476
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wvla-3.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca -O2" } */
+
+// Make sure we don't warn on VLA with -Walloca.
+
+void f (void*);
+
+void h1 (unsigned n)
+{
+  int a [n];
+  f (a);
+}
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 36299a6..57b61f4 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -469,6 +469,7 @@ extern simple_ipa_opt_pass *make_pass_ipa_oacc (gcc::context *ctxt);
 extern simple_ipa_opt_pass *make_pass_ipa_oacc_kernels (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_gen_hsail (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_warn_nonnull_compare (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_walloca (gcc::context *ctxt);
 
 /* IPA Passes */
 extern simple_ipa_opt_pass *make_pass_ipa_lower_emutls (gcc::context *ctxt);

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-15 17:05   ` Aldy Hernandez
@ 2016-07-16 21:08     ` Martin Sebor
  2016-07-16 23:59       ` Martin Sebor
  2016-07-18 10:45       ` Aldy Hernandez
  2016-07-17 15:53     ` Manuel López-Ibáñez
  1 sibling, 2 replies; 26+ messages in thread
From: Martin Sebor @ 2016-07-16 21:08 UTC (permalink / raw)
  To: Aldy Hernandez, gcc-patches, Martin Sebor, Jeff Law; +Cc: Andrew MacLeod

> Done.  -Walloca and -Wvla warn on any use of alloca and VLAs
> accordingly, with or without optimization.  I sorry() on the bounded cases.

I think it's an improvement though I suspect we each have a slightly
different understanding of what the sorry message is meant to be used
for.  It's documented in the Diagnostics Conventions section of the
GCC Coding Conventions as:

   sorry is for correct user input programs but unimplemented
   functionalities.

I take that to mean that it should be used for what is considered
valid user input that cannot be processed because the functionality
is not yet implemented (but eventually will be).  So unless this
case falls into this category I would expect GCC to issue a warning
saying that the options have no effect (or limited effect, whatever
the case may be) without optimization. But maybe I'm not reading
the coding conventions text right.

>> 2) When passed an argument of a signed type, GCC prints
>>
>>    warning: cast from signed type in alloca
>>
>> even though there is no explicit cast in the code.  It may not
>> be obvious why the conversion is a problem in this context.  I
>> would suggest to rephrase the warning along the lines of
>> -Wsign-conversion which prints:
>>
>>    conversion to ‘long unsigned int’ from ‘int’ may change the sign of
>> the result
>>
>> and add why it's a potential problem.  Perhaps something like:
>>
>>    argument to alloca may be too large due to conversion from
>>    'int to 'long unsigned int'
>
> Fixed:

Cool.

FWIW, by coincidence I was just educated about the subtle nuances
of quoting in GCC messages in a discussion with David and Manu.
Types, functions, variables, and literals that appear in the source
code should be referenced in diagnostics by using the "%qT", "%qD",
and "%qE" directives so that GCC can add the right quotes and
highlighting.  Enclosing "'%T'" in quotes will not use the same
kind of quotes as "%qT" and won't highlight the type name.

   https://gcc.gnu.org/wiki/DiagnosticsGuidelines

> There is a "documented" reason for this: :)
>
>        // Do not warn on VLAs occurring in a loop, since VLAs are
>        // guaranteed to be cleaned up when they go out of scope.
>        // That is, there is a corresponding __builtin_stack_restore
>        // at the end of the scope in which the VLA occurs.

Yes, I understand that VLAs in loops are treated differently than
alloca.  But I don't think this is quite how the logic should work.
I.e., an excessively large VLA should be diagnosed regardless of
whether it's in a loop or outside.  Consider the following case
where with the patch as is, the warning is issued only for one
of the two functions, even though they both allocate a VLA in
excess of the threshold.

   #define FOO(n) if (1) { \
       char a [n]; \
       f (a); \
     } else (void)0

   #define BAR(n) do { \
       char a [n]; \
       f (a); \
     } while (0)

   void f (void*);

   void foo (void)
   {
     int n = 8000;
     FOO (n);        // warning with -Wla-larger-than=4000
   }

   void bar (void)
   {
     int n = 8000;
     BAR (n);        // no warning
   }

>> 5) The -Wvla=N logic only seems to take into consideration the number
>> of elements but not the size of the element type. For example, I wasn't
>> able to get it to warn on the following with -Wvla=255 or greater:
>>
>>    void f0 (void*);
>>
>>    void f1 (unsigned char a)
>>    {
>>      int x [a];   // or even char a [n][__INT_MAX__];
>>      f0 (x);
>>    }
>
> That was a huge oversight (or should I say over-engineering) on my part.
>   Fixed.

Looks good.

I did notice one minor glitch, though not one caused by your patch.
GCC apparently transforms simple VLAs that are 256 bytes or less
in size into ordinary arrays (i.e., it doesn't call
__builtin_alloca_with_align).  Because of that, specifying
-Wvla-larger-than=N with N less than 256 may not give a warning,
as in the example below.  I suspect there may not be anything
the Walloca pass can do about this so perhaps just mentioning
it in the manual might be enough to avoid bug reports about false
negatives.

   void f0 (void*);

   unsigned f1 (void) { return 256; }

   void f2 (void)
   {
     unsigned n = f1 ();
     char a [n];
     f0 (a);
   }

GCC doesn't do the same transformation for alloca calls so the
-Walloca-larger-than warning doesn't have this quirk.

> This is a problem with the generic machinery so I would prefer someone
> file a bugzilla report :), as this affects other options.

I raised bug 71905 for this.

> Ughhh...you're making me write user friendly stuff.  The reason I got
> into compilers was so I wouldn't have to deal with the user :).
>
>    if (n < 2000)
>      {
>      p = __builtin_alloca (n);
>      f (p);
>      }
>
> ./cc1 a.c -fdump-tree-all-vops-alias-details-graph -quiet -I/tmp
> -Walloca-larger-than=100 -O2
> a.c: In function ‘g2’:
> a.c:9:7: warning: argument to alloca may be too large
> [-Walloca-larger-than=]
>       p = __builtin_alloca (n);
>       ~~^~~~~~~~~~~~~~~~~~~~~~
> a.c:9:7: note: limit is '100' bytes, but argument may be '1999'
>
> Happy? :-)

I along with untold numbers of users thank you! :)

(As another quoting nit, unlike functions, variables, and constants
that appear in the source code, ordinary numbers apparently aren't
supposed to be quoted in GCC messages.  (I'm guilty of making this
mistake in at least two of my own patches and will be correcting
it.)

Martin

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-16 21:08     ` Martin Sebor
@ 2016-07-16 23:59       ` Martin Sebor
  2016-07-18 10:45       ` Aldy Hernandez
  1 sibling, 0 replies; 26+ messages in thread
From: Martin Sebor @ 2016-07-16 23:59 UTC (permalink / raw)
  To: Aldy Hernandez, gcc-patches, Martin Sebor, Jeff Law; +Cc: Andrew MacLeod

I forgot to ask, Aldy:  Have you tried using LTO with the warning?
I haven't managed to get it to warn even though I expected it to.
The test I used is below.

[...more testing...]

After some more testing I discovered that LTO somehow seems to
suppress this and other warnings (including the new -Wformat-length
I've been working on).  I haven't spent any time figuring out why
but I have raised bug 71907 for it.

Thanks
Martin

$ (CC='/build/gcc-walloca/gcc/xgcc -B /build/gcc-walloca/gcc'; 
CFLAGS='-O2 -Wall -Wextra -Wpedantic -Walloca-larger-than=32 -flto'; cat 
x.c && $CC -c x.c && $CC -DMAIN -DN=12345678 -c -o main.o x.c && $CC 
$CFLAGS x.o main.o && gdb -batch -q -ex r -ex bt ./a.out )
extern void f0 (void*, void*);
extern unsigned f1 (void);
extern void f2 (void);

#if MAIN
void f0 (void *p, void *q) {
   __builtin_printf ("p = %p, q = %p, d = %td\n", p, q, (char*)p - 
(char*)q);
}

unsigned f1 (void) { return N; }

int main (void) { f2 (); }

#else

void f2 (void)
{
   void *p = &p;
   void *q = __builtin_alloca (f1 ());
   f0 (p, q);
}

#endif

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400592 in f2 ()
#0  0x0000000000400592 in f2 ()
#1  0x00000000004005e9 in main ()

On 07/16/2016 03:07 PM, Martin Sebor wrote:
>> Done.  -Walloca and -Wvla warn on any use of alloca and VLAs
>> accordingly, with or without optimization.  I sorry() on the bounded
>> cases.
>
> I think it's an improvement though I suspect we each have a slightly
> different understanding of what the sorry message is meant to be used
> for.  It's documented in the Diagnostics Conventions section of the
> GCC Coding Conventions as:
>
>    sorry is for correct user input programs but unimplemented
>    functionalities.
>
> I take that to mean that it should be used for what is considered
> valid user input that cannot be processed because the functionality
> is not yet implemented (but eventually will be).  So unless this
> case falls into this category I would expect GCC to issue a warning
> saying that the options have no effect (or limited effect, whatever
> the case may be) without optimization. But maybe I'm not reading
> the coding conventions text right.
>
>>> 2) When passed an argument of a signed type, GCC prints
>>>
>>>    warning: cast from signed type in alloca
>>>
>>> even though there is no explicit cast in the code.  It may not
>>> be obvious why the conversion is a problem in this context.  I
>>> would suggest to rephrase the warning along the lines of
>>> -Wsign-conversion which prints:
>>>
>>>    conversion to ‘long unsigned int’ from ‘int’ may change the sign of
>>> the result
>>>
>>> and add why it's a potential problem.  Perhaps something like:
>>>
>>>    argument to alloca may be too large due to conversion from
>>>    'int to 'long unsigned int'
>>
>> Fixed:
>
> Cool.
>
> FWIW, by coincidence I was just educated about the subtle nuances
> of quoting in GCC messages in a discussion with David and Manu.
> Types, functions, variables, and literals that appear in the source
> code should be referenced in diagnostics by using the "%qT", "%qD",
> and "%qE" directives so that GCC can add the right quotes and
> highlighting.  Enclosing "'%T'" in quotes will not use the same
> kind of quotes as "%qT" and won't highlight the type name.
>
>    https://gcc.gnu.org/wiki/DiagnosticsGuidelines
>
>> There is a "documented" reason for this: :)
>>
>>        // Do not warn on VLAs occurring in a loop, since VLAs are
>>        // guaranteed to be cleaned up when they go out of scope.
>>        // That is, there is a corresponding __builtin_stack_restore
>>        // at the end of the scope in which the VLA occurs.
>
> Yes, I understand that VLAs in loops are treated differently than
> alloca.  But I don't think this is quite how the logic should work.
> I.e., an excessively large VLA should be diagnosed regardless of
> whether it's in a loop or outside.  Consider the following case
> where with the patch as is, the warning is issued only for one
> of the two functions, even though they both allocate a VLA in
> excess of the threshold.
>
>    #define FOO(n) if (1) { \
>        char a [n]; \
>        f (a); \
>      } else (void)0
>
>    #define BAR(n) do { \
>        char a [n]; \
>        f (a); \
>      } while (0)
>
>    void f (void*);
>
>    void foo (void)
>    {
>      int n = 8000;
>      FOO (n);        // warning with -Wla-larger-than=4000
>    }
>
>    void bar (void)
>    {
>      int n = 8000;
>      BAR (n);        // no warning
>    }
>
>>> 5) The -Wvla=N logic only seems to take into consideration the number
>>> of elements but not the size of the element type. For example, I wasn't
>>> able to get it to warn on the following with -Wvla=255 or greater:
>>>
>>>    void f0 (void*);
>>>
>>>    void f1 (unsigned char a)
>>>    {
>>>      int x [a];   // or even char a [n][__INT_MAX__];
>>>      f0 (x);
>>>    }
>>
>> That was a huge oversight (or should I say over-engineering) on my part.
>>   Fixed.
>
> Looks good.
>
> I did notice one minor glitch, though not one caused by your patch.
> GCC apparently transforms simple VLAs that are 256 bytes or less
> in size into ordinary arrays (i.e., it doesn't call
> __builtin_alloca_with_align).  Because of that, specifying
> -Wvla-larger-than=N with N less than 256 may not give a warning,
> as in the example below.  I suspect there may not be anything
> the Walloca pass can do about this so perhaps just mentioning
> it in the manual might be enough to avoid bug reports about false
> negatives.
>
>    void f0 (void*);
>
>    unsigned f1 (void) { return 256; }
>
>    void f2 (void)
>    {
>      unsigned n = f1 ();
>      char a [n];
>      f0 (a);
>    }
>
> GCC doesn't do the same transformation for alloca calls so the
> -Walloca-larger-than warning doesn't have this quirk.
>
>> This is a problem with the generic machinery so I would prefer someone
>> file a bugzilla report :), as this affects other options.
>
> I raised bug 71905 for this.
>
>> Ughhh...you're making me write user friendly stuff.  The reason I got
>> into compilers was so I wouldn't have to deal with the user :).
>>
>>    if (n < 2000)
>>      {
>>      p = __builtin_alloca (n);
>>      f (p);
>>      }
>>
>> ./cc1 a.c -fdump-tree-all-vops-alias-details-graph -quiet -I/tmp
>> -Walloca-larger-than=100 -O2
>> a.c: In function ‘g2’:
>> a.c:9:7: warning: argument to alloca may be too large
>> [-Walloca-larger-than=]
>>       p = __builtin_alloca (n);
>>       ~~^~~~~~~~~~~~~~~~~~~~~~
>> a.c:9:7: note: limit is '100' bytes, but argument may be '1999'
>>
>> Happy? :-)
>
> I along with untold numbers of users thank you! :)
>
> (As another quoting nit, unlike functions, variables, and constants
> that appear in the source code, ordinary numbers apparently aren't
> supposed to be quoted in GCC messages.  (I'm guilty of making this
> mistake in at least two of my own patches and will be correcting
> it.)
>
> Martin

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-15 17:05   ` Aldy Hernandez
  2016-07-16 21:08     ` Martin Sebor
@ 2016-07-17 15:53     ` Manuel López-Ibáñez
  2016-07-18 10:10       ` Aldy Hernandez
  2016-07-19 17:47       ` Jeff Law
  1 sibling, 2 replies; 26+ messages in thread
From: Manuel López-Ibáñez @ 2016-07-17 15:53 UTC (permalink / raw)
  To: Aldy Hernandez, Martin Sebor, gcc-patches, Martin Sebor, Jeff Law
  Cc: Andrew MacLeod

On 15/07/16 18:05, Aldy Hernandez wrote:

+    case OPT_Walloca_larger_than_:
+      if (!value)
+	inform (loc, "-Walloca-larger-than=0 is meaningless");
+      break;
+
+    case OPT_Wvla_larger_than_:
+      if (!value)
+	inform (loc, "-Wvla-larger-than=0 is meaningless");
+      break;
+

We don't give similar notes for any of the other Wx-larger-than= options. If 
-Wvla-larger-than=0 suppresses a previous -Wvla-larger-than=, then it doesn't 
seem meaningless, but a useful thing to have.

+  if (is_vla)
+    gcc_assert (warn_vla_limit > 0);
+  if (!is_vla)
+    gcc_assert (warn_alloca_limit > 0);

if-else ? Or perhaps:

gcc_assert (!is_vla || warn_vla_limit > 0);
gcc_assert (is_vla || warn_alloca_limit > 0);

--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -275,6 +275,15 @@ Wall
  C ObjC C++ ObjC++ Warning
  Enable most warning messages.

+Walloca
+C ObjC C++ ObjC++ Var(warn_alloca) Warning
+
+Walloca-larger-than=
+C ObjC C++ ObjC++ Var(warn_alloca_limit) Warning Joined RejectNegative UInteger
+-Walloca-larger-than=<number> Warn on unbounded uses of
+alloca, and on bounded uses of alloca whose bound can be larger than
+<number> bytes.

No description for Walloca.

+	      if (warn_alloca)
+		warning_at (loc, OPT_Walloca, "use of alloca");
+	      continue;

Since alloca is a source code entity, it would be good to quote it using %< %> 
(this hints translators to not translate it).


+	  const char *alloca_str
+	    = is_vla ? "variable-length array" : "alloca";
+	  char buff[WIDE_INT_MAX_PRECISION / 4 + 4];
+	  switch (w)
+	    {
+	    case ALLOCA_OK:
+	      break;
+	    case ALLOCA_BOUND_MAYBE_LARGE:
+	      gcc_assert (assumed_limit != 0);
+	      if (warning_at (loc, wcode,
+			      "argument to %s may be too large", alloca_str))
+		{
+		  print_decu (assumed_limit, buff);
+		  inform (loc, "limit is '%u' bytes, but argument may be '%s'",
+			  is_vla ? warn_vla_limit : warn_alloca_limit, buff);
+		}
+	      break;
+	    case ALLOCA_BOUND_DEFINITELY_LARGE:
+	      gcc_assert (assumed_limit != 0);
+	      if (warning_at (loc, wcode,
+			      "argument to %s is too large", alloca_str))
+		{
+		  print_decu (assumed_limit, buff);
+		  inform (loc, "limit is %u' bytes, but argument is '%s'",
+			  is_vla ? warn_vla_limit : warn_alloca_limit, buff);
+		}
+	      break;

https://gcc.gnu.org/codingconventions.html#Diagnostics :

All diagnostics should be full sentences without English fragments substituted 
in them, to facilitate translation.

Example:

if (warning_at (loc, wcode,
		is_vla ? "argument to variable-length array may be too large"
                        : "argument to %<alloca%> may be too large"))

+ print_decu (assumed_limit, buff);
+ inform (loc, "limit is '%u' bytes, but argument may be '%s'",
+ is_vla ? warn_vla_limit : warn_alloca_limit, buff);
+ }

https://gcc.gnu.org/wiki/DiagnosticsGuidelines#Quoting :
Other elements such as numbers that do no refer to numeric constants that 
appear in the source code should not be quoted.

+	      warning_at (loc, wcode, "argument to %s may be too large due to "
+			  "conversion from '%T' to '%T'",
+			  alloca_str, invalid_casted_type, size_type_node);

 From the same link:

Text should be quoted by either using the q modifier in a directive such as 
%qE, or by enclosing the quoted text in a pair of %< and %> directives, and 
never by using explicit quote characters. The directives handle the appropriate 
quote characters for each language and apply the correct color or highlighting.

I don't think the above are critical problems, they could be fixed by a follow 
up patch.

Cheers,
	Manuel.

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-17 15:53     ` Manuel López-Ibáñez
@ 2016-07-18 10:10       ` Aldy Hernandez
  2016-07-19 17:47       ` Jeff Law
  1 sibling, 0 replies; 26+ messages in thread
From: Aldy Hernandez @ 2016-07-18 10:10 UTC (permalink / raw)
  To: Manuel López-Ibáñez, Martin Sebor, gcc-patches,
	Martin Sebor, Jeff Law
  Cc: Andrew MacLeod

On 07/17/2016 11:52 AM, Manuel López-Ibáñez wrote:
> On 15/07/16 18:05, Aldy Hernandez wrote:
>
> +    case OPT_Walloca_larger_than_:
> +      if (!value)
> +    inform (loc, "-Walloca-larger-than=0 is meaningless");
> +      break;
> +
> +    case OPT_Wvla_larger_than_:
> +      if (!value)
> +    inform (loc, "-Wvla-larger-than=0 is meaningless");
> +      break;
> +
>
> We don't give similar notes for any of the other Wx-larger-than=
> options. If -Wvla-larger-than=0 suppresses a previous
> -Wvla-larger-than=, then it doesn't seem meaningless, but a useful thing
> to have.

I'm trying to avoid confusing users that may think that 
-Walloca-larger-than=0 means warn on any use of alloca.  That is what 
-Walloca is for.  But really, I don't care.  If you feel strongly about 
it, I can just remove the block of code.

Aldy

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-16 21:08     ` Martin Sebor
  2016-07-16 23:59       ` Martin Sebor
@ 2016-07-18 10:45       ` Aldy Hernandez
  2016-07-19  3:14         ` Martin Sebor
  1 sibling, 1 reply; 26+ messages in thread
From: Aldy Hernandez @ 2016-07-18 10:45 UTC (permalink / raw)
  To: Martin Sebor, gcc-patches, Martin Sebor, Jeff Law; +Cc: Andrew MacLeod

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

On 07/16/2016 05:07 PM, Martin Sebor wrote:

[Addressed all of Manu's suggestions as well.]

>> Done.  -Walloca and -Wvla warn on any use of alloca and VLAs
>> accordingly, with or without optimization.  I sorry() on the bounded
>> cases.
>
> I think it's an improvement though I suspect we each have a slightly
> different understanding of what the sorry message is meant to be used
> for.  It's documented in the Diagnostics Conventions section of the
> GCC Coding Conventions as:
>
>    sorry is for correct user input programs but unimplemented
>    functionalities.
>
> I take that to mean that it should be used for what is considered
> valid user input that cannot be processed because the functionality
> is not yet implemented (but eventually will be).  So unless this
> case falls into this category I would expect GCC to issue a warning
> saying that the options have no effect (or limited effect, whatever
> the case may be) without optimization. But maybe I'm not reading
> the coding conventions text right.

Technically we could add the functionality later.  I don't know whether 
the new range info work can be made to work with lower optimization 
levels.  But really, I don't care :).  Adjusted to a warning.

>
>>> 2) When passed an argument of a signed type, GCC prints
>>>
>>>    warning: cast from signed type in alloca
>>>
>>> even though there is no explicit cast in the code.  It may not
>>> be obvious why the conversion is a problem in this context.  I
>>> would suggest to rephrase the warning along the lines of
>>> -Wsign-conversion which prints:
>>>
>>>    conversion to ‘long unsigned int’ from ‘int’ may change the sign of
>>> the result
>>>
>>> and add why it's a potential problem.  Perhaps something like:
>>>
>>>    argument to alloca may be too large due to conversion from
>>>    'int to 'long unsigned int'
>>
>> Fixed:
>
> Cool.
>
> FWIW, by coincidence I was just educated about the subtle nuances
> of quoting in GCC messages in a discussion with David and Manu.
> Types, functions, variables, and literals that appear in the source
> code should be referenced in diagnostics by using the "%qT", "%qD",
> and "%qE" directives so that GCC can add the right quotes and
> highlighting.  Enclosing "'%T'" in quotes will not use the same
> kind of quotes as "%qT" and won't highlight the type name.

Fixed.

>
>    https://gcc.gnu.org/wiki/DiagnosticsGuidelines
>
>> There is a "documented" reason for this: :)
>>
>>        // Do not warn on VLAs occurring in a loop, since VLAs are
>>        // guaranteed to be cleaned up when they go out of scope.
>>        // That is, there is a corresponding __builtin_stack_restore
>>        // at the end of the scope in which the VLA occurs.
>
> Yes, I understand that VLAs in loops are treated differently than
> alloca.  But I don't think this is quite how the logic should work.
> I.e., an excessively large VLA should be diagnosed regardless of
> whether it's in a loop or outside.  Consider the following case
> where with the patch as is, the warning is issued only for one
> of the two functions, even though they both allocate a VLA in
> excess of the threshold.

Agreed...

>
>    #define FOO(n) if (1) { \
>        char a [n]; \
>        f (a); \
>      } else (void)0
>
>    #define BAR(n) do { \
>        char a [n]; \
>        f (a); \
>      } while (0)
>
>    void f (void*);
>
>    void foo (void)
>    {
>      int n = 8000;
>      FOO (n);        // warning with -Wla-larger-than=4000
>    }
>
>    void bar (void)
>    {
>      int n = 8000;
>      BAR (n);        // no warning
>    }

...though it looks like your testcases may get optimized away.

I've added this testcase:

void
f6 (unsigned stuff)
{
   int n = 7000;
   do {
     char a[n]; // { dg-warning "variable-length array is too large" }
     f0 (a);
   } while (stuff--);
}


I've changed the logic so we warn on large allocas whether they're for 
VLAs or otherwise, but no warning given on VLAs within a loop when we 
know the bounds.

>
>>> 5) The -Wvla=N logic only seems to take into consideration the number
>>> of elements but not the size of the element type. For example, I wasn't
>>> able to get it to warn on the following with -Wvla=255 or greater:
>>>
>>>    void f0 (void*);
>>>
>>>    void f1 (unsigned char a)
>>>    {
>>>      int x [a];   // or even char a [n][__INT_MAX__];
>>>      f0 (x);
>>>    }
>>
>> That was a huge oversight (or should I say over-engineering) on my part.
>>   Fixed.
>
> Looks good.
>
> I did notice one minor glitch, though not one caused by your patch.
> GCC apparently transforms simple VLAs that are 256 bytes or less
> in size into ordinary arrays (i.e., it doesn't call
> __builtin_alloca_with_align).  Because of that, specifying
> -Wvla-larger-than=N with N less than 256 may not give a warning,
> as in the example below.  I suspect there may not be anything
> the Walloca pass can do about this so perhaps just mentioning
> it in the manual might be enough to avoid bug reports about false
> negatives.

Documentation updated.

>
>    void f0 (void*);
>
>    unsigned f1 (void) { return 256; }
>
>    void f2 (void)
>    {
>      unsigned n = f1 ();
>      char a [n];
>      f0 (a);
>    }
>
> GCC doesn't do the same transformation for alloca calls so the
> -Walloca-larger-than warning doesn't have this quirk.
>
>> This is a problem with the generic machinery so I would prefer someone
>> file a bugzilla report :), as this affects other options.
>
> I raised bug 71905 for this.
>
>> Ughhh...you're making me write user friendly stuff.  The reason I got
>> into compilers was so I wouldn't have to deal with the user :).
>>
>>    if (n < 2000)
>>      {
>>      p = __builtin_alloca (n);
>>      f (p);
>>      }
>>
>> ./cc1 a.c -fdump-tree-all-vops-alias-details-graph -quiet -I/tmp
>> -Walloca-larger-than=100 -O2
>> a.c: In function ‘g2’:
>> a.c:9:7: warning: argument to alloca may be too large
>> [-Walloca-larger-than=]
>>       p = __builtin_alloca (n);
>>       ~~^~~~~~~~~~~~~~~~~~~~~~
>> a.c:9:7: note: limit is '100' bytes, but argument may be '1999'
>>
>> Happy? :-)
>
> I along with untold numbers of users thank you! :)
>
> (As another quoting nit, unlike functions, variables, and constants
> that appear in the source code, ordinary numbers apparently aren't
> supposed to be quoted in GCC messages.  (I'm guilty of making this
> mistake in at least two of my own patches and will be correcting
> it.)

Fixed.

How does this look?

Aldy


[-- Attachment #2: curr --]
[-- Type: text/plain, Size: 34654 bytes --]

gcc/

	* Makefile.in (OBJS): Add gimple-ssa-warn-walloca.o.
	* passes.def: Add two instances of pass_walloca.
	* tree-pass.h (make_pass_walloca): New.
	* gimple-ssa-warn-walloca.c: New file.
	* opts.c (finish_options): Warn when using -Wvla-larger-than= and
	-Walloca-larger-than= without -O2 or greater.
	* doc/invoke.texi: Document -Walloca, -Walloca-larger-than=, and
	-Wvla-larger-than= options.

gcc/c-family/

	* c.opt (Walloca): New.
	(Walloca-larger-than=): New.
	(Wvla-larger-than=): New.

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 776f6d7..2a13b8f 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1284,6 +1284,7 @@ OBJS = \
 	gimple-ssa-nonnull-compare.o \
 	gimple-ssa-split-paths.o \
 	gimple-ssa-strength-reduction.o \
+	gimple-ssa-warn-alloca.o \
 	gimple-streamer-in.o \
 	gimple-streamer-out.o \
 	gimple-walk.o \
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index ff6339c..dc2be2d 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -376,6 +376,16 @@ c_common_handle_option (size_t scode, const char *arg, int value,
       cpp_opts->warn_num_sign_change = value;
       break;
 
+    case OPT_Walloca_larger_than_:
+      if (!value)
+	inform (loc, "-Walloca-larger-than=0 is meaningless");
+      break;
+
+    case OPT_Wvla_larger_than_:
+      if (!value)
+	inform (loc, "-Wvla-larger-than=0 is meaningless");
+      break;
+
     case OPT_Wunknown_pragmas:
       /* Set to greater than 1, so that even unknown pragmas in
 	 system headers will be warned about.  */
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 83fd84c..1d4ebf0 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -275,6 +275,16 @@ Wall
 C ObjC C++ ObjC++ Warning
 Enable most warning messages.
 
+Walloca
+C ObjC C++ ObjC++ Var(warn_alloca) Warning
+Warn on any use of alloca.
+
+Walloca-larger-than=
+C ObjC C++ ObjC++ Var(warn_alloca_limit) Warning Joined RejectNegative UInteger
+-Walloca-larger-than=<number> Warn on unbounded uses of
+alloca, and on bounded uses of alloca whose bound can be larger than
+<number> bytes.
+
 Warray-bounds
 LangEnabledBy(C ObjC C++ ObjC++,Wall)
 ; in common.opt
@@ -980,6 +990,12 @@ Wvla
 C ObjC C++ ObjC++ Var(warn_vla) Init(-1) Warning
 Warn if a variable length array is used.
 
+Wvla-larger-than=
+C ObjC C++ ObjC++ Var(warn_vla_limit) Warning Joined RejectNegative UInteger
+-Wvla-larger-than=<number> Warn on unbounded uses of variable-length arrays, and
+on bounded uses of variable-length arrays whose bound can be
+larger than <number> bytes.
+
 Wvolatile-register-var
 C ObjC C++ ObjC++ Var(warn_volatile_register_var) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
 Warn when a register variable is declared volatile.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 2105351..3847b24 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -253,6 +253,7 @@ Objective-C and Objective-C++ Dialects}.
 @gccoptlist{-fsyntax-only  -fmax-errors=@var{n}  -Wpedantic @gol
 -pedantic-errors @gol
 -w  -Wextra  -Wall  -Waddress  -Waggregate-return  @gol
+-Walloca -Walloca-larger-than=@var{n} @gol
 -Wno-aggressive-loop-optimizations -Warray-bounds -Warray-bounds=@var{n} @gol
 -Wno-attributes -Wbool-compare -Wno-builtin-macro-redefined @gol
 -Wc90-c99-compat -Wc99-c11-compat @gol
@@ -309,7 +310,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wunused-const-variable -Wunused-const-variable=@var{n} @gol
 -Wunused-but-set-parameter -Wunused-but-set-variable @gol
 -Wuseless-cast -Wvariadic-macros -Wvector-operation-performance @gol
--Wvla -Wvolatile-register-var  -Wwrite-strings @gol
+-Wvla -Wvla-larger-than=@var{n} -Wvolatile-register-var  -Wwrite-strings @gol
 -Wzero-as-null-pointer-constant -Whsa}
 
 @item C and Objective-C-only Warning Options
@@ -4618,6 +4619,61 @@ annotations.
 Warn about overriding virtual functions that are not marked with the override
 keyword.
 
+@item -Walloca
+@opindex Wno-alloca
+@opindex Walloca
+This option warns on all uses of @code{alloca} in the source.
+
+@item -Walloca-larger-than=@var{n}
+This option warns on calls to @code{alloca} that are not bounded by a
+controlling predicate limiting its size to @var{n} bytes, or calls to
+@code{alloca} where the bound is unknown.
+
+For example, a bounded case of @code{alloca} could be:
+
+@smallexample
+unsigned int n;
+...
+if (n <= 1000)
+  alloca (n);
+@end smallexample
+
+In the above example, passing @code{-Walloca=1000} would not issue a
+warning because the call to @code{alloca} is known to be at most 1000
+bytes.  However, if @code{-Walloca=500} was passed, the compiler would
+have emitted a warning.
+
+Unbounded uses, on the other hand, are uses of @code{alloca} with no
+controlling predicate verifying its size.  For example:
+
+@smallexample
+stuff ();
+alloca (n);
+@end smallexample
+
+If @code{-Walloca=500} was passed, the above would trigger a warning,
+but this time because of the lack of bounds checking.
+
+Note, that even seemingly correct code involving signed integers could
+cause a warning:
+
+@smallexample
+signed int n;
+...
+if (n < 500)
+  alloca (n);
+@end smallexample
+
+In the above example, @var{n} could be negative, causing a larger than
+expected argument to be implicitly casted into the @code{alloca} call.
+
+This option also warns when @code{alloca} is used in a loop.
+
+This warning is not enabled by @option{-Wall}, and is only active when
+@option{-ftree-vrp} is active (default for @option{-O2} and above).
+
+See also @option{-Wvla-larger-than=@var{n}}.
+
 @item -Warray-bounds
 @itemx -Warray-bounds=@var{n}
 @opindex Wno-array-bounds
@@ -5782,9 +5838,25 @@ moving from a moved-from object, this warning can be disabled.
 @item -Wvla
 @opindex Wvla
 @opindex Wno-vla
-Warn if variable length array is used in the code.
+Warn if a variable-length array is used in the code.
 @option{-Wno-vla} prevents the @option{-Wpedantic} warning of
-the variable length array.
+the variable-length array.
+
+@item -Wvla-larger-than=@var{n}
+If this option is used, the compiler will warn on uses of
+variable-length arrays where the size is either unbounded, or bounded
+by an argument that can be larger than @var{n} bytes.  This is similar
+to how @option{-Walloca-larger-than=@var{n}} works, but with
+variable-length arrays.
+
+Note that GCC may optimize small variable-length arrays of a known
+value into plain arrays, so this warning may not get triggered for
+such arrays.
+
+This warning is not enabled by @option{-Wall}, and is only active when
+@option{-ftree-vrp} is active (default for @option{-O2} and above).
+
+See also @option{-Walloca-larger-than=@var{n}}.
 
 @item -Wvolatile-register-var
 @opindex Wvolatile-register-var
diff --git a/gcc/gimple-ssa-warn-alloca.c b/gcc/gimple-ssa-warn-alloca.c
new file mode 100644
index 0000000..37f2b66
--- /dev/null
+++ b/gcc/gimple-ssa-warn-alloca.c
@@ -0,0 +1,513 @@
+/* Warn on problematic uses of alloca and variable length arrays.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Contributed by Aldy Hernandez <aldyh@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+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/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "ssa.h"
+#include "gimple-pretty-print.h"
+#include "diagnostic-core.h"
+#include "fold-const.h"
+#include "gimple-iterator.h"
+#include "tree-ssa.h"
+#include "params.h"
+#include "tree-cfg.h"
+#include "calls.h"
+#include "cfgloop.h"
+
+const pass_data pass_data_walloca = {
+  GIMPLE_PASS,
+  "walloca",
+  OPTGROUP_NONE,
+  TV_NONE,
+  PROP_cfg, // properties_required
+  0,	    // properties_provided
+  0,	    // properties_destroyed
+  0,	    // properties_start
+  0,	    // properties_finish
+};
+
+class pass_walloca : public gimple_opt_pass
+{
+public:
+  pass_walloca (gcc::context *ctxt)
+    : gimple_opt_pass(pass_data_walloca, ctxt), first_time_p (false)
+  {}
+  opt_pass *clone () { return new pass_walloca (m_ctxt); }
+  void set_pass_param (unsigned int n, bool param)
+    {
+      gcc_assert (n == 0);
+      first_time_p = param;
+    }
+  virtual bool gate (function *);
+  virtual unsigned int execute (function *);
+
+ private:
+  // Set to TRUE the first time we run this pass on a function.
+  bool first_time_p;
+};
+
+bool
+pass_walloca::gate (function *fun ATTRIBUTE_UNUSED)
+{
+  // The first time this pass is called, it is called before
+  // optimizations have been run and range information is unavailable,
+  // so we can only perform strict alloca checking.
+  if (first_time_p)
+    return warn_alloca != 0;
+
+  return warn_alloca_limit > 0 || warn_vla_limit > 0;
+}
+
+// Possible problematic uses of alloca.
+enum alloca_type {
+  // Alloca argument is within known bounds that are appropriate.
+  ALLOCA_OK,
+
+  // Alloca argument is KNOWN to have a value that is too large.
+  ALLOCA_BOUND_DEFINITELY_LARGE,
+
+  // Alloca argument may be too large.
+  ALLOCA_BOUND_MAYBE_LARGE,
+
+  // Alloca argument is bounded but of an indeterminate size.
+  ALLOCA_BOUND_UNKNOWN,
+
+  // Alloca argument was casted from a signed integer.
+  ALLOCA_CAST_FROM_SIGNED,
+
+  // Alloca appears in a loop.
+  ALLOCA_IN_LOOP,
+
+  // Alloca argument is 0.
+  ALLOCA_ARG_IS_ZERO,
+
+  // Alloca call is unbounded.  That is, there is no controlling
+  // predicate for its argument.
+  ALLOCA_UNBOUNDED
+};
+
+// We have a few heuristics up our sleeve to determine if a call to
+// alloca() is within bounds.  Try them out and return the type of
+// alloca call this is based on its argument.
+//
+// Given a known argument (ARG) to alloca() and an EDGE (E)
+// calculating said argument, verify that the last statement in the BB
+// in E->SRC is a gate comparing ARG to an acceptable bound for
+// alloca().  See examples below.
+//
+// MAX_SIZE is WARN_ALLOCA= adjusted for VLAs.  It is the maximum size
+// in bytes we allow for arg.
+//
+// If the alloca bound is determined to be too large, ASSUMED_LIMIT is
+// set to the bound used to determine this.  ASSUMED_LIMIT is only set
+// for ALLOCA_BOUND_MAYBE_LARGE and ALLOCA_BOUND_DEFINITELY_LARGE.
+//
+// Returns the alloca type.
+
+static enum alloca_type
+alloca_call_type_by_arg (tree arg, edge e, unsigned max_size,
+			 wide_int *assumed_limit)
+{
+  // All the tests bellow depend on the jump being on the TRUE path.
+  if (!(e->flags & EDGE_TRUE_VALUE))
+    return ALLOCA_UNBOUNDED;
+
+  basic_block bb = e->src;
+  gimple_stmt_iterator gsi = gsi_last_bb (bb);
+  gimple *last = gsi_stmt (gsi);
+  if (!last || gimple_code (last) != GIMPLE_COND)
+    return ALLOCA_UNBOUNDED;
+
+  /* Check for:
+     if (ARG <= N)
+       goto <bb 3>;
+      else
+        goto <bb 4>;
+      <bb 3>:
+      alloca(ARG);
+  */
+  if (gimple_cond_code (last) == LE_EXPR
+      && gimple_cond_lhs (last) == arg)
+    {
+      if (TREE_CODE (gimple_cond_rhs (last)) == INTEGER_CST)
+	{
+	  tree rhs = gimple_cond_rhs (last);
+	  if (tree_to_uhwi (rhs) > max_size)
+	    {
+	      *assumed_limit = rhs;
+	      return ALLOCA_BOUND_MAYBE_LARGE;
+	    }
+	  return ALLOCA_OK;
+	}
+      else
+	return ALLOCA_BOUND_UNKNOWN;
+    }
+
+  /* Check for:
+     if (arg .cond. LIMIT) -or- if (LIMIT .cond. arg)
+       alloca(arg);
+
+     Where LIMIT has a bound of unknown range.  */
+  tree limit = NULL;
+  if (gimple_cond_lhs (last) == arg)
+    limit = gimple_cond_rhs (last);
+  else if (gimple_cond_rhs (last) == arg)
+    limit = gimple_cond_lhs (last);
+  if (limit && TREE_CODE (limit) == SSA_NAME)
+    {
+      wide_int min, max;
+      value_range_type range_type = get_range_info (limit, &min, &max);
+      if (range_type == VR_UNDEFINED || range_type == VR_VARYING)
+	return ALLOCA_BOUND_UNKNOWN;
+      // FIXME: We could try harder here and handle a possible range
+      // or anti-range.  Hopefully the upcoming changes to range info
+      // will give us finer grained info, and we can avoid somersaults
+      // here.
+    }
+
+  return ALLOCA_UNBOUNDED;
+}
+
+// Return TRUE if SSA's definition is a cast from a signed type.
+// If so, set *INVALID_CASTED_TYPE to the signed type.
+
+static bool
+cast_from_signed_p (tree ssa, tree *invalid_casted_type)
+{
+  gimple *def = SSA_NAME_DEF_STMT (ssa);
+  if (def
+      && !gimple_nop_p (def)
+      && gimple_assign_cast_p (def)
+      && !TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (def))))
+    {
+      *invalid_casted_type = TREE_TYPE (gimple_assign_rhs1 (def));
+      return true;
+    }
+  return false;
+}
+
+// Return TURE if X has a maximum range of MAX, basically covering the
+// entire domain, in which case it's no range at all.
+
+static bool
+is_max (tree x, wide_int max)
+{
+  return wi::max_value (TREE_TYPE (x)) == max;
+}
+
+// Analyze the alloca call in STMT and return an `enum alloca_type'
+// explaining what type of alloca it is.  IS_VLA is set if the alloca
+// call is really a BUILT_IN_ALLOCA_WITH_ALIGN, signifying a VLA.
+//
+// If the alloca bound is determined to be too large, ASSUMED_LIMIT is
+// set to the bound used to determine this.  ASSUMED_LIMIT is only set
+// for ALLOCA_BOUND_MAYBE_LARGE and ALLOCA_BOUND_DEFINITELY_LARGE.
+//
+// If the alloca call may be too large because of a cast from a signed
+// type to an unsigned type, set *INVALID_CASTED_TYPE to the
+// problematic signed type.
+
+static enum alloca_type
+alloca_call_type (gimple *stmt, bool is_vla, wide_int *assumed_limit,
+		  tree *invalid_casted_type)
+{
+  gcc_assert (gimple_alloca_call_p (stmt));
+  tree len = gimple_call_arg (stmt, 0);
+  enum alloca_type w = ALLOCA_UNBOUNDED;
+  wide_int min, max;
+
+  gcc_assert (!is_vla || warn_vla_limit > 0);
+  gcc_assert (is_vla || warn_alloca_limit > 0);
+
+  // Adjust warn_alloca_max_size for VLAs, by taking the underlying
+  // type into account.
+  unsigned HOST_WIDE_INT max_size;
+  if (is_vla)
+    max_size = (unsigned HOST_WIDE_INT) warn_vla_limit;
+  else
+    max_size = (unsigned HOST_WIDE_INT) warn_alloca_limit;
+
+  // Check for the obviously bounded case.
+  if (TREE_CODE (len) == INTEGER_CST)
+    {
+      if (tree_to_uhwi (len) > max_size)
+	{
+	  *assumed_limit = len;
+	  return ALLOCA_BOUND_DEFINITELY_LARGE;
+	}
+      if (integer_zerop (len))
+	return ALLOCA_ARG_IS_ZERO;
+      w = ALLOCA_OK;
+    }
+  else if (TREE_CODE (len) != SSA_NAME)
+    return ALLOCA_UNBOUNDED;
+  // Check the range info if available.
+  else
+    {
+      if (value_range_type range_type = get_range_info (len, &min, &max))
+	{
+	  if (range_type == VR_RANGE)
+	    {
+	      if (wi::leu_p (max, max_size))
+		w = ALLOCA_OK;
+	      else if (is_max (len, max))
+		{
+		  // A cast may have created a range we don't care
+		  // about.  For instance, a cast from 16-bit to
+		  // 32-bit creates a range of 0..65535, even if there
+		  // is not really a determinable range in the
+		  // underlying code.  In this case, look through the
+		  // cast at the original argument, and fall through
+		  // to look at other alternatives.
+		  gimple *def = SSA_NAME_DEF_STMT (len);
+		  if (gimple_assign_cast_p (def))
+		    len = gimple_assign_rhs1 (def);
+		}
+	      else
+		{
+		  /* If `len' is merely a cast that is being
+		     calculated right before the call to alloca, look
+		     at the range for the original value.
+
+		     This avoids the cast creating a range where the
+		     original expression did not have a range:
+
+		     # RANGE [0, 18446744073709551615] NONZERO 4294967295
+		     _2 = (long unsigned int) n_7(D);
+		     p_9 = __builtin_alloca (_2);
+
+		     The correct thing would've been for the user to
+		     use size_t, which in the case above would've been
+		     'long unsigned int', and everything would've
+		     worked.  But we have to catch cases where the
+		     user is using some other compatible type for the
+		     call argument to alloca (say unsigned short).  */
+		  gimple *def = SSA_NAME_DEF_STMT (len);
+		  if (gimple_assign_cast_p (def))
+		    {
+		      len = gimple_assign_rhs1 (def);
+		      range_type = get_range_info (len, &min, &max);
+		    }
+
+		  if (range_type != VR_VARYING && is_max (len, max))
+		    {
+		      // Treat a max of the entire domain as if it had no
+		      // range info, and fall through the try other
+		      // alternatives.
+		    }
+		  else
+		    {
+		      *assumed_limit = max;
+		      return ALLOCA_BOUND_MAYBE_LARGE;
+		    }
+		}
+	    }
+	  else if (range_type == VR_ANTI_RANGE)
+	    {
+	      // There may be some wrapping around going on.  Catch it
+	      // with this heuristic.  Hopefully, this VR_ANTI_RANGE
+	      // nonsense will go away, and we won't have to catch the
+	      // sign conversion problems with this crap.
+	      if (cast_from_signed_p (len, invalid_casted_type))
+		return ALLOCA_CAST_FROM_SIGNED;
+
+	      // Fall thru and try other things.
+	    }
+	  else if (range_type == VR_VARYING)
+	    {
+	      // No easily determined range.  Try other things.
+	    }
+	}
+    }
+
+  // If we couldn't find anything, try a few heuristics for things we
+  // can easily determine.  Check these misc cases but only accept
+  // them if all predecessors have a known bound.
+  basic_block bb = gimple_bb (stmt);
+  if (w == ALLOCA_UNBOUNDED)
+    {
+      w = ALLOCA_OK;
+      for (unsigned ix = 0; ix < EDGE_COUNT (bb->preds); ix++)
+	{
+	  enum alloca_type w
+	    = alloca_call_type_by_arg (len, EDGE_PRED (bb, ix), max_size,
+				       assumed_limit);
+	  if (w != ALLOCA_OK)
+	    return w;
+	}
+    }
+
+  return w;
+}
+
+// Return TRUE if the alloca call in STMT is in a loop.
+
+static bool
+in_loop_p (bool is_vla, gimple *stmt)
+{
+  basic_block bb = gimple_bb (stmt);
+  if (bb->loop_father
+      // ?? Functions with no loops get a loop_father?  I
+      // don't get it.  The following conditional seems to do
+      // the trick to exclude such nonsense.
+      && bb->loop_father->header != ENTRY_BLOCK_PTR_FOR_FN (cfun))
+    {
+      // Do not warn on VLAs occurring in a loop, since VLAs are
+      // guaranteed to be cleaned up when they go out of scope.
+      // That is, there is a corresponding __builtin_stack_restore
+      // at the end of the scope in which the VLA occurs.
+      tree fndecl = gimple_call_fn (stmt);
+      while (TREE_CODE (fndecl) == ADDR_EXPR)
+	fndecl = TREE_OPERAND (fndecl, 0);
+      if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+	  && is_vla
+	  && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA_WITH_ALIGN)
+	return false;
+
+      return true;
+    }
+  return false;
+}
+
+unsigned int
+pass_walloca::execute (function *fun)
+{
+  basic_block bb;
+  FOR_EACH_BB_FN (bb, fun)
+    {
+      for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);
+	   gsi_next (&si))
+	{
+	  gimple *stmt = gsi_stmt (si);
+	  location_t loc = gimple_location (stmt);
+
+	  if (!gimple_alloca_call_p (stmt))
+	    continue;
+	  gcc_assert (gimple_call_num_args (stmt) >= 1);
+
+	  bool is_vla = gimple_alloca_call_p (stmt)
+	    && gimple_call_alloca_for_var_p (as_a <gcall *> (stmt));
+
+	  // Strict mode whining for VLAs is handled by the front-end,
+	  // so we can safely ignore this case.  Also, ignore VLAs if
+	  // the user doesn't care about them.
+	  if (is_vla
+	      && (warn_vla > 0 || !warn_vla_limit))
+	    continue;
+
+	  if (!is_vla && (warn_alloca || !warn_alloca_limit))
+	    {
+	      if (warn_alloca)
+		warning_at (loc, OPT_Walloca, "use of %<alloca%>");
+	      continue;
+	    }
+
+	  wide_int assumed_limit
+	    = wi::to_wide (integer_zero_node,
+			   TYPE_PRECISION (size_type_node));
+	  tree invalid_casted_type = NULL;
+	  enum alloca_type w = alloca_call_type (stmt, is_vla, &assumed_limit,
+						 &invalid_casted_type);
+
+	  // Even if we think the alloca call is OK, make sure it's
+	  // not in a loop.
+	  if (w == ALLOCA_OK && in_loop_p (is_vla, stmt))
+	    w = ALLOCA_IN_LOOP;
+
+	  enum opt_code wcode
+	    = is_vla ? OPT_Wvla_larger_than_ : OPT_Walloca_larger_than_;
+	  char buff[WIDE_INT_MAX_PRECISION / 4 + 4];
+	  switch (w)
+	    {
+	    case ALLOCA_OK:
+	      break;
+	    case ALLOCA_BOUND_MAYBE_LARGE:
+	      gcc_assert (assumed_limit != 0);
+	      if (warning_at (loc, wcode,
+			      is_vla ? "argument to variable-length array "
+			      "may be too large"
+			      : "argument to %<alloca%> may be too large"))
+		{
+		  print_decu (assumed_limit, buff);
+		  inform (loc, "limit is %u bytes, but argument may be %s",
+			  is_vla ? warn_vla_limit : warn_alloca_limit, buff);
+		}
+	      break;
+	    case ALLOCA_BOUND_DEFINITELY_LARGE:
+	      gcc_assert (assumed_limit != 0);
+	      if (warning_at (loc, wcode,
+			      is_vla ? "argument to variable-length array "
+			      "is too large"
+			      : "argument to %<alloca%> is too large"))
+		{
+		  print_decu (assumed_limit, buff);
+		  inform (loc, "limit is %u bytes, but argument is %s",
+			  is_vla ? warn_vla_limit : warn_alloca_limit, buff);
+		}
+	      break;
+	    case ALLOCA_BOUND_UNKNOWN:
+	      warning_at (loc, wcode,
+			  is_vla ? "variable-length array bound is unknown"
+			  : "%<alloca%> bound is unknown");
+	      break;
+	    case ALLOCA_UNBOUNDED:
+	      warning_at (loc, wcode,
+			  is_vla ? "unbounded use of variable-length array"
+			  : "unbounded use of %<alloca%>");
+	      break;
+	    case ALLOCA_IN_LOOP:
+	      warning_at (loc, wcode,
+			  is_vla ? "use of variable-length array "
+			  "within a loop"
+			  : "use of %<alloca%> within a loop");
+	      break;
+	    case ALLOCA_CAST_FROM_SIGNED:
+	      gcc_assert (invalid_casted_type != NULL_TREE);
+	      warning_at (loc, wcode,
+			  is_vla ? "argument to variable-length array "
+			  "may be too large due to "
+			  "conversion from %qT to %qT"
+			  : "argument to %<alloca%> may be too large due to "
+			  "conversion from %qT to %qT",
+			  invalid_casted_type, size_type_node);
+	      break;
+	    case ALLOCA_ARG_IS_ZERO:
+	      warning_at (loc, wcode,
+			  is_vla ? "argument to variable-length array is zero"
+			  : "argument to %<alloca%> is zero");
+	      break;
+	    default:
+	      gcc_unreachable ();
+	    }
+	}
+    }
+  return 0;
+}
+
+gimple_opt_pass *
+make_pass_walloca (gcc::context *ctxt)
+{
+  return new pass_walloca (ctxt);
+}
diff --git a/gcc/opts.c b/gcc/opts.c
index e80331f..7cdb4bf 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -743,6 +743,20 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
   if (opts->x_flag_tm && opts->x_flag_non_call_exceptions)
     sorry ("transactional memory is not supported with non-call exceptions");
 
+  // -Walloca-larger-than=N needs range info which is only available at -O2.
+  if (opts->x_warn_alloca_limit > 0 && opts->x_optimize < 2)
+    {
+      warning_at (loc, 0, "-Walloca-larger-than=N ignored without -O2");
+      opts->x_warn_alloca_limit = 0;
+    }
+
+  // -Wvla-larger-than= needs range info which is only available at -O2.
+  if (opts->x_warn_vla_limit > 0 && opts->x_optimize < 2)
+    {
+      warning_at (loc, 0, "-Wvla-larger-than= ignored without -O2");
+      opts->x_warn_vla_limit = 0;
+    }
+
   /* Unless the user has asked for section anchors, we disable toplevel
      reordering at -O0 to disable transformations that might be surprising
      to end users and to get -fno-toplevel-reorder tested.  */
diff --git a/gcc/passes.def b/gcc/passes.def
index 3647e90..591add2 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3.  If not see
   NEXT_PASS (pass_warn_function_return);
   NEXT_PASS (pass_expand_omp);
   NEXT_PASS (pass_build_cgraph_edges);
+  NEXT_PASS (pass_walloca, /*strict_mode_p=*/true);
   TERMINATE_PASS_LIST (all_lowering_passes)
 
   /* Interprocedural optimization passes.  */
@@ -303,6 +304,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_simduid_cleanup);
       NEXT_PASS (pass_lower_vector_ssa);
       NEXT_PASS (pass_cse_reciprocals);
+      NEXT_PASS (pass_walloca, /*strict_mode_p=*/false);
       NEXT_PASS (pass_reassoc, false /* insert_powi_p */);
       NEXT_PASS (pass_strength_reduction);
       NEXT_PASS (pass_split_paths);
diff --git a/gcc/testsuite/gcc.dg/Walloca-1.c b/gcc/testsuite/gcc.dg/Walloca-1.c
new file mode 100644
index 0000000..34a20c3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-1.c
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=2000 -O2" } */
+
+#define alloca __builtin_alloca
+
+typedef __SIZE_TYPE__ size_t;
+extern size_t strlen(const char *);
+
+extern void useit (char *);
+
+int num;
+
+void foo1 (size_t len, size_t len2, size_t len3)
+{
+  int i;
+
+  for (i=0; i < 123; ++i)
+    {
+      char *s = alloca (566);	/* { dg-warning "'alloca' within a loop" } */
+      useit (s);
+    }
+
+  char *s = alloca (123);
+  useit (s);			// OK, constant argument to alloca
+
+  s = alloca (num);		// { dg-warning "large due to conversion" }
+  useit (s);
+
+  s = alloca(90000);		/* { dg-warning "is too large" } */
+  useit (s);
+
+  if (len < 2000)
+    {
+      s = alloca(len);		// OK, bounded
+      useit (s);
+    }
+
+  if (len + len2 < 2000)	// OK, bounded
+    {
+      s = alloca(len + len2);
+      useit (s);
+    }
+
+  if (len3 <= 2001)
+    {
+      s = alloca(len3);		/* { dg-warning "may be too large" } */
+      useit(s);
+    }
+}
+
+void foo2 (__SIZE_TYPE__ len)
+{
+  // Test that a direct call to __builtin_alloca_with_align is not confused
+  // with a VLA.
+  void *p = __builtin_alloca_with_align (len, 8); // { dg-warning "unbounded use of 'alloca'" }
+  useit (p);
+}
+
+void foo3 (unsigned char a)
+{
+  if (a == 0)
+    useit (__builtin_alloca (a)); // { dg-warning "argument to 'alloca' is zero" }
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-2.c b/gcc/testsuite/gcc.dg/Walloca-2.c
new file mode 100644
index 0000000..8ab1d92
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-2.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=2000 -O2" } */
+
+void f (void *);
+
+void
+g1 (int n)
+{
+  void *p;
+  if (n > 0 && n < 2000)
+    p = __builtin_alloca (n);
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
+
+void
+g2 (int n)
+{
+  void *p;
+  if (n < 2000)
+    p = __builtin_alloca (n); // { dg-warning "large due to conversion" }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
+
+void
+g3 (int n)
+{
+  void *p;
+  if (n > 0 && n < 3000)
+    {
+      p = __builtin_alloca (n); // { dg-warning "'alloca' may be too large" }
+      // { dg-message "note:.*argument may be 2999" "note" { target *-*-* } 34 }
+    }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-3.c b/gcc/testsuite/gcc.dg/Walloca-3.c
new file mode 100644
index 0000000..5345197
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-3.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=2000 -O2" } */
+
+void f (void *);
+
+__SIZE_TYPE__ LIMIT;
+
+// Warn when there is an alloca bound, but it is an unknown bound.
+
+void
+g1 (__SIZE_TYPE__ n)
+{
+  void *p;
+  if (n < LIMIT)
+    p = __builtin_alloca (n); // { dg-warning "'alloca' bound is unknown" }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
+
+// Similar to the above, but do not get confused by the upcast.
+
+unsigned short SHORT_LIMIT;
+void
+g2 (unsigned short n)
+{
+  void *p;
+  if (n < SHORT_LIMIT)
+    p = __builtin_alloca (n); // { dg-warning "'alloca' bound is unknown" }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-4.c b/gcc/testsuite/gcc.dg/Walloca-4.c
new file mode 100644
index 0000000..d96cc4e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-4.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=5000 -O2" } */
+/* { dg-xfail-if "Currently broken but Andrew's work should fix this" { *-*-* } } */
+
+// Should be another variant of Walloca-7.c.
+// This should not warn, as we have a known bound within limits.
+
+ char *
+ _i18n_number_rewrite (char *w, char *rear_ptr)
+{
+
+  char *src;
+ _Bool 
+      use_alloca = (((rear_ptr - w) * sizeof (char)) < 4096U);
+ if (use_alloca)
+    src = (char *) __builtin_alloca ((rear_ptr - w) * sizeof (char));
+  else
+    src = (char *) __builtin_malloc ((rear_ptr - w) * sizeof (char));
+  return src;
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-5.c b/gcc/testsuite/gcc.dg/Walloca-5.c
new file mode 100644
index 0000000..5ed1171
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-5.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=123 -O2" } */
+/* { dg-xfail-if "Currently broken but Andrew's work should fix this" { *-*-* } } */
+
+/* The argument to alloca ends up having a range of 0..MAXINT(32bits),
+   so we think we have a range because of the upcast.  Consequently,
+   we warn with "alloca may be too large", but we should technically
+   warn with "unbounded use of alloca".
+
+   We currently drill through casts to figure this stuff out, but we
+   get confused because it's not just a cast.  It's a cast, plus a
+   multiply.
+
+   <bb 2>:
+  # RANGE [0, 4294967295] NONZERO 4294967295
+  _1 = (long unsigned int) something_4(D);
+  # RANGE [0, 34359738360] NONZERO 34359738360
+  _2 = _1 * 8;
+  _3 = __builtin_alloca (_2);
+
+  I don't know whether it's even worth such fine-grained warnings.
+  Perhaps we should generically warn everywhere with "alloca may be
+  too large".
+
+  I'm hoping that this particular case will be easier to diagnose with
+  Andrew's work.  */
+
+void useit(void *);
+void foobar(unsigned int something)
+{
+  useit(__builtin_alloca (something * sizeof (const char *))); // { dg-warning "unbounded use of alloca" "" { xfail *-*-* } }
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-6.c b/gcc/testsuite/gcc.dg/Walloca-6.c
new file mode 100644
index 0000000..b4d8d41
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-6.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=256 -O2" } */
+/* { dg-xfail-if "Currently broken but Andrew's work should fix this" { *-*-* } } */
+
+void f (void*);
+void g (__SIZE_TYPE__ n)
+{
+  // No warning on this case.  Range is easily determinable.
+  if (n > 0 && n < 256)
+    f (__builtin_alloca (n));
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-7.c b/gcc/testsuite/gcc.dg/Walloca-7.c
new file mode 100644
index 0000000..d6581a5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-7.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca -O0" } */
+
+extern void f(void *);
+
+void foo(void)
+{
+  // Test that strict -Walloca works even without optimization.
+  f (__builtin_alloca(500)); // { dg-warning "use of 'alloca'" }
+}
+
+void bar(void)
+{
+  // Test that we warn on alloca() calls, not just __builtin_alloca calls.
+  extern void *alloca(__SIZE_TYPE__);
+  f (alloca (123)); // { dg-warning "use of 'alloca'" }
+}
diff --git a/gcc/testsuite/gcc.dg/Wvla-1.c b/gcc/testsuite/gcc.dg/Wvla-1.c
new file mode 100644
index 0000000..384c930
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wvla-1.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-Wvla-larger-than=100 -O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern void useit (char *);
+
+int num;
+
+void test_vlas (size_t num)
+{
+  char str2[num];		/* { dg-warning "unbounded use" } */
+  useit(str2);
+
+  num = 98;
+  for (int i=0; i < 1234; ++i) {
+    char str[num];	        // OK, VLA in a loop, but it is a
+				// known size *AND* the compiler takes
+				// care of cleaning up between
+				// iterations with
+				// __builtin_stack_restore.
+    useit(str);
+  }
+}
diff --git a/gcc/testsuite/gcc.dg/Wvla-2.c b/gcc/testsuite/gcc.dg/Wvla-2.c
new file mode 100644
index 0000000..0ab2a45
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wvla-2.c
@@ -0,0 +1,70 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target stdint_types } */
+/* { dg-options "-O2 -Wvla-larger-than=40" } */
+
+#include <stdint.h>
+
+void f0 (void *);
+void
+f1 (__SIZE_TYPE__ a)
+{
+  if (a <= 10)
+    {
+      // 10 * 4 bytes = 40: OK!
+      uint32_t x[a];
+      f0 (x);
+    }
+}
+
+void
+f2 (__SIZE_TYPE__ a)
+{
+  if (a <= 11)
+    {
+      // 11 * 4 bytes = 44: Not OK.
+      uint32_t x[a]; // { dg-warning "array may be too large" }
+      // { dg-message "note:.*argument may be 44" "note" { target *-*-* } 25 }
+      f0 (x);
+    }
+}
+
+void
+f3 (__SIZE_TYPE__ a, __SIZE_TYPE__ b)
+{
+  if (a <= 5 && b <= 3)
+    {
+      // 5 * 3 * 4 bytes = 60: Not OK.
+      uint32_t x[a][b]; // { dg-warning "array may be too large" }
+      f0 (x);
+    }
+}
+
+void
+f4 (__SIZE_TYPE__ a, __SIZE_TYPE__ b)
+{
+  if (a <= 5 && b <= 2)
+    {
+      // 5 * 2 * 4 bytes = 40 bytes: OK!
+      uint32_t x[a][b];
+      f0 (x);
+    }
+}
+
+void
+f5 (__SIZE_TYPE__ len)
+{
+  // Test that a direct call to __builtin_alloca_with_align is not
+  // confused with a VLA.
+  void *p = __builtin_alloca_with_align (len, 8);
+  f0 (p);
+}
+
+void
+f6 (unsigned stuff)
+{
+  int n = 7000;
+  do {
+    char a[n]; // { dg-warning "variable-length array is too large" }
+    f0 (a);
+  } while (stuff--);
+}
diff --git a/gcc/testsuite/gcc.dg/Wvla-3.c b/gcc/testsuite/gcc.dg/Wvla-3.c
new file mode 100644
index 0000000..5124476
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wvla-3.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca -O2" } */
+
+// Make sure we don't warn on VLA with -Walloca.
+
+void f (void*);
+
+void h1 (unsigned n)
+{
+  int a [n];
+  f (a);
+}
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 36299a6..57b61f4 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -469,6 +469,7 @@ extern simple_ipa_opt_pass *make_pass_ipa_oacc (gcc::context *ctxt);
 extern simple_ipa_opt_pass *make_pass_ipa_oacc_kernels (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_gen_hsail (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_warn_nonnull_compare (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_walloca (gcc::context *ctxt);
 
 /* IPA Passes */
 extern simple_ipa_opt_pass *make_pass_ipa_lower_emutls (gcc::context *ctxt);

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-18 10:45       ` Aldy Hernandez
@ 2016-07-19  3:14         ` Martin Sebor
  2016-07-19 11:03           ` Aldy Hernandez
  0 siblings, 1 reply; 26+ messages in thread
From: Martin Sebor @ 2016-07-19  3:14 UTC (permalink / raw)
  To: Aldy Hernandez, gcc-patches, Martin Sebor, Jeff Law; +Cc: Andrew MacLeod

> How does this look?

I think it's 99% there.  You've addressed all of my comments so
far -- thanks for that and for being so patient.  I realize it
would be a lot more efficient to get all the feedback (or as much
of it as possible) up front.  Unfortunately, some things don't get
noticed until round 2 or 3 (or even 4).  Please take this in lieu
of an apology for not spotting the issues below until now(*).

For this code:

   void f (void*);

   void g (int n)
   {
     int a [n];
     f (a);
   }

-Wvla-larger-than=32 prints:

   warning: argument to variable-length array may be too large
   note: limit is 32 bytes, but argument may be 18446744073709551612

An int argument cannot be that large.  I suspect the printed value
is actually the size of the VLA in bytes when N is -1, truncated
to size_t, rather than the value of the VLA bound.  To avoid
confusion the note should be corrected to say something like:

   note: limit is 32 bytes, but the variable-length array may be
   as large as 18446744073709551612

Also, the checker prints false positives for code like:

   void f (void*);

   void g (unsigned x, int *y)
   {
     if (1000 < x) return;

     while (*y) {
       char a [x];
       f (a);
     }
   }

With -Wvla-larger-than=1000 and greater it prints:

   warning: unbounded use of variable-length array

(Same thing with alloca).  There should be no warning for VLAs,
and for alloca, the warning should say "use of variable-length
array within a loop."  The VRP dump suggests the range information
is available within the loop.  Is the get_range_info() function
not returning the corresponding bounds?

Martin

[*] If you want to get me back I invite you (with a bit of
selfishness ;-) to review my -Wformat-length patch.

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-19  3:14         ` Martin Sebor
@ 2016-07-19 11:03           ` Aldy Hernandez
  2016-07-19 17:54             ` Jeff Law
  2016-08-01 20:35             ` Joseph Myers
  0 siblings, 2 replies; 26+ messages in thread
From: Aldy Hernandez @ 2016-07-19 11:03 UTC (permalink / raw)
  To: Martin Sebor, gcc-patches, Martin Sebor, Jeff Law; +Cc: Andrew MacLeod

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

On 07/18/2016 11:14 PM, Martin Sebor wrote:
>> How does this look?
>
> I think it's 99% there.  You've addressed all of my comments so
> far -- thanks for that and for being so patient.  I realize it
> would be a lot more efficient to get all the feedback (or as much
> of it as possible) up front.  Unfortunately, some things don't get
> noticed until round 2 or 3 (or even 4).  Please take this in lieu
> of an apology for not spotting the issues below until now(*).

No problem, although I think we're getting to the point of diminishing 
returns with regards to functionality.  It may be best to involve Jeff 
or another global reviewer at this point for a review.  We can address 
any more minor things as a follow-up patch.  (Unless you find any show 
stoppers before then :)).

>
> For this code:
>
>    void f (void*);
>
>    void g (int n)
>    {
>      int a [n];
>      f (a);
>    }
>
> -Wvla-larger-than=32 prints:
>
>    warning: argument to variable-length array may be too large
>    note: limit is 32 bytes, but argument may be 18446744073709551612
>
> An int argument cannot be that large.  I suspect the printed value
> is actually the size of the VLA in bytes when N is -1, truncated
> to size_t, rather than the value of the VLA bound.  To avoid
> confusion the note should be corrected to say something like:
>
>    note: limit is 32 bytes, but the variable-length array may be
>    as large as 18446744073709551612

Note adjusted.

>
> Also, the checker prints false positives for code like:
>
>    void f (void*);
>
>    void g (unsigned x, int *y)
>    {
>      if (1000 < x) return;
>
>      while (*y) {
>        char a [x];
>        f (a);
>      }
>    }
>
> With -Wvla-larger-than=1000 and greater it prints:
>
>    warning: unbounded use of variable-length array
>
> (Same thing with alloca).  There should be no warning for VLAs,
> and for alloca, the warning should say "use of variable-length
> array within a loop."  The VRP dump suggests the range information
> is available within the loop.  Is the get_range_info() function
> not returning the corresponding bounds?

This is a false positive, but there's little we can do with the current 
range infrastructure.  The range information becomes less precise the 
further down the optimization pipeline we get.  So, even though as far 
as *.c.126t.crited1, we still see appropriate range information:

    # RANGE [0, 1000] NONZERO 1023
    _10 = (sizetype) x_3(D);
...
    a.1_12 = __builtin_alloca_with_align (_10, 8);

The PRE pass cleans things up in such a way that we end up with:

    <bb 2>:
    if (x_3(D) > 1000)
      goto <bb 8>;
    else
      goto <bb 3>;
...
    <bb 3>:
    # VUSE <.MEM_2(D)>
    _16 = *y_1(D);
    if (_16 != 0)
      goto <bb 9>;
    else
      goto <bb 8>;

    <bb 9>:

    <bb 4>:
    # <-----------------NO RANGE INFO--------->
    _4 = (sizetype) x_3(D);

...

a.1_12 = __builtin_alloca_with_align (_4, 8);

The -Walloca pass comes after PRE, which means we no longer have any 
range information for _4, and chasing the IL to glean this information 
would be fragile at best.  We will just have to live with this until we 
have better pervasive range information.

Updated patch tested on x86-64 Linux.

Aldy


[-- Attachment #2: curr --]
[-- Type: text/plain, Size: 34860 bytes --]

gcc/

	* Makefile.in (OBJS): Add gimple-ssa-warn-walloca.o.
	* passes.def: Add two instances of pass_walloca.
	* tree-pass.h (make_pass_walloca): New.
	* gimple-ssa-warn-walloca.c: New file.
	* opts.c (finish_options): Warn when using -Wvla-larger-than= and
	-Walloca-larger-than= without -O2 or greater.
	* doc/invoke.texi: Document -Walloca, -Walloca-larger-than=, and
	-Wvla-larger-than= options.

gcc/c-family/

	* c.opt (Walloca): New.
	(Walloca-larger-than=): New.
	(Wvla-larger-than=): New.

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 776f6d7..2a13b8f 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1284,6 +1284,7 @@ OBJS = \
 	gimple-ssa-nonnull-compare.o \
 	gimple-ssa-split-paths.o \
 	gimple-ssa-strength-reduction.o \
+	gimple-ssa-warn-alloca.o \
 	gimple-streamer-in.o \
 	gimple-streamer-out.o \
 	gimple-walk.o \
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index ff6339c..dc2be2d 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -376,6 +376,16 @@ c_common_handle_option (size_t scode, const char *arg, int value,
       cpp_opts->warn_num_sign_change = value;
       break;
 
+    case OPT_Walloca_larger_than_:
+      if (!value)
+	inform (loc, "-Walloca-larger-than=0 is meaningless");
+      break;
+
+    case OPT_Wvla_larger_than_:
+      if (!value)
+	inform (loc, "-Wvla-larger-than=0 is meaningless");
+      break;
+
     case OPT_Wunknown_pragmas:
       /* Set to greater than 1, so that even unknown pragmas in
 	 system headers will be warned about.  */
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 83fd84c..1d4ebf0 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -275,6 +275,16 @@ Wall
 C ObjC C++ ObjC++ Warning
 Enable most warning messages.
 
+Walloca
+C ObjC C++ ObjC++ Var(warn_alloca) Warning
+Warn on any use of alloca.
+
+Walloca-larger-than=
+C ObjC C++ ObjC++ Var(warn_alloca_limit) Warning Joined RejectNegative UInteger
+-Walloca-larger-than=<number> Warn on unbounded uses of
+alloca, and on bounded uses of alloca whose bound can be larger than
+<number> bytes.
+
 Warray-bounds
 LangEnabledBy(C ObjC C++ ObjC++,Wall)
 ; in common.opt
@@ -980,6 +990,12 @@ Wvla
 C ObjC C++ ObjC++ Var(warn_vla) Init(-1) Warning
 Warn if a variable length array is used.
 
+Wvla-larger-than=
+C ObjC C++ ObjC++ Var(warn_vla_limit) Warning Joined RejectNegative UInteger
+-Wvla-larger-than=<number> Warn on unbounded uses of variable-length arrays, and
+on bounded uses of variable-length arrays whose bound can be
+larger than <number> bytes.
+
 Wvolatile-register-var
 C ObjC C++ ObjC++ Var(warn_volatile_register_var) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
 Warn when a register variable is declared volatile.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 2105351..3847b24 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -253,6 +253,7 @@ Objective-C and Objective-C++ Dialects}.
 @gccoptlist{-fsyntax-only  -fmax-errors=@var{n}  -Wpedantic @gol
 -pedantic-errors @gol
 -w  -Wextra  -Wall  -Waddress  -Waggregate-return  @gol
+-Walloca -Walloca-larger-than=@var{n} @gol
 -Wno-aggressive-loop-optimizations -Warray-bounds -Warray-bounds=@var{n} @gol
 -Wno-attributes -Wbool-compare -Wno-builtin-macro-redefined @gol
 -Wc90-c99-compat -Wc99-c11-compat @gol
@@ -309,7 +310,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wunused-const-variable -Wunused-const-variable=@var{n} @gol
 -Wunused-but-set-parameter -Wunused-but-set-variable @gol
 -Wuseless-cast -Wvariadic-macros -Wvector-operation-performance @gol
--Wvla -Wvolatile-register-var  -Wwrite-strings @gol
+-Wvla -Wvla-larger-than=@var{n} -Wvolatile-register-var  -Wwrite-strings @gol
 -Wzero-as-null-pointer-constant -Whsa}
 
 @item C and Objective-C-only Warning Options
@@ -4618,6 +4619,61 @@ annotations.
 Warn about overriding virtual functions that are not marked with the override
 keyword.
 
+@item -Walloca
+@opindex Wno-alloca
+@opindex Walloca
+This option warns on all uses of @code{alloca} in the source.
+
+@item -Walloca-larger-than=@var{n}
+This option warns on calls to @code{alloca} that are not bounded by a
+controlling predicate limiting its size to @var{n} bytes, or calls to
+@code{alloca} where the bound is unknown.
+
+For example, a bounded case of @code{alloca} could be:
+
+@smallexample
+unsigned int n;
+...
+if (n <= 1000)
+  alloca (n);
+@end smallexample
+
+In the above example, passing @code{-Walloca=1000} would not issue a
+warning because the call to @code{alloca} is known to be at most 1000
+bytes.  However, if @code{-Walloca=500} was passed, the compiler would
+have emitted a warning.
+
+Unbounded uses, on the other hand, are uses of @code{alloca} with no
+controlling predicate verifying its size.  For example:
+
+@smallexample
+stuff ();
+alloca (n);
+@end smallexample
+
+If @code{-Walloca=500} was passed, the above would trigger a warning,
+but this time because of the lack of bounds checking.
+
+Note, that even seemingly correct code involving signed integers could
+cause a warning:
+
+@smallexample
+signed int n;
+...
+if (n < 500)
+  alloca (n);
+@end smallexample
+
+In the above example, @var{n} could be negative, causing a larger than
+expected argument to be implicitly casted into the @code{alloca} call.
+
+This option also warns when @code{alloca} is used in a loop.
+
+This warning is not enabled by @option{-Wall}, and is only active when
+@option{-ftree-vrp} is active (default for @option{-O2} and above).
+
+See also @option{-Wvla-larger-than=@var{n}}.
+
 @item -Warray-bounds
 @itemx -Warray-bounds=@var{n}
 @opindex Wno-array-bounds
@@ -5782,9 +5838,25 @@ moving from a moved-from object, this warning can be disabled.
 @item -Wvla
 @opindex Wvla
 @opindex Wno-vla
-Warn if variable length array is used in the code.
+Warn if a variable-length array is used in the code.
 @option{-Wno-vla} prevents the @option{-Wpedantic} warning of
-the variable length array.
+the variable-length array.
+
+@item -Wvla-larger-than=@var{n}
+If this option is used, the compiler will warn on uses of
+variable-length arrays where the size is either unbounded, or bounded
+by an argument that can be larger than @var{n} bytes.  This is similar
+to how @option{-Walloca-larger-than=@var{n}} works, but with
+variable-length arrays.
+
+Note that GCC may optimize small variable-length arrays of a known
+value into plain arrays, so this warning may not get triggered for
+such arrays.
+
+This warning is not enabled by @option{-Wall}, and is only active when
+@option{-ftree-vrp} is active (default for @option{-O2} and above).
+
+See also @option{-Walloca-larger-than=@var{n}}.
 
 @item -Wvolatile-register-var
 @opindex Wvolatile-register-var
diff --git a/gcc/gimple-ssa-warn-alloca.c b/gcc/gimple-ssa-warn-alloca.c
new file mode 100644
index 0000000..065a72b
--- /dev/null
+++ b/gcc/gimple-ssa-warn-alloca.c
@@ -0,0 +1,517 @@
+/* Warn on problematic uses of alloca and variable length arrays.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Contributed by Aldy Hernandez <aldyh@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+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/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "ssa.h"
+#include "gimple-pretty-print.h"
+#include "diagnostic-core.h"
+#include "fold-const.h"
+#include "gimple-iterator.h"
+#include "tree-ssa.h"
+#include "params.h"
+#include "tree-cfg.h"
+#include "calls.h"
+#include "cfgloop.h"
+
+const pass_data pass_data_walloca = {
+  GIMPLE_PASS,
+  "walloca",
+  OPTGROUP_NONE,
+  TV_NONE,
+  PROP_cfg, // properties_required
+  0,	    // properties_provided
+  0,	    // properties_destroyed
+  0,	    // properties_start
+  0,	    // properties_finish
+};
+
+class pass_walloca : public gimple_opt_pass
+{
+public:
+  pass_walloca (gcc::context *ctxt)
+    : gimple_opt_pass(pass_data_walloca, ctxt), first_time_p (false)
+  {}
+  opt_pass *clone () { return new pass_walloca (m_ctxt); }
+  void set_pass_param (unsigned int n, bool param)
+    {
+      gcc_assert (n == 0);
+      first_time_p = param;
+    }
+  virtual bool gate (function *);
+  virtual unsigned int execute (function *);
+
+ private:
+  // Set to TRUE the first time we run this pass on a function.
+  bool first_time_p;
+};
+
+bool
+pass_walloca::gate (function *fun ATTRIBUTE_UNUSED)
+{
+  // The first time this pass is called, it is called before
+  // optimizations have been run and range information is unavailable,
+  // so we can only perform strict alloca checking.
+  if (first_time_p)
+    return warn_alloca != 0;
+
+  return warn_alloca_limit > 0 || warn_vla_limit > 0;
+}
+
+// Possible problematic uses of alloca.
+enum alloca_type {
+  // Alloca argument is within known bounds that are appropriate.
+  ALLOCA_OK,
+
+  // Alloca argument is KNOWN to have a value that is too large.
+  ALLOCA_BOUND_DEFINITELY_LARGE,
+
+  // Alloca argument may be too large.
+  ALLOCA_BOUND_MAYBE_LARGE,
+
+  // Alloca argument is bounded but of an indeterminate size.
+  ALLOCA_BOUND_UNKNOWN,
+
+  // Alloca argument was casted from a signed integer.
+  ALLOCA_CAST_FROM_SIGNED,
+
+  // Alloca appears in a loop.
+  ALLOCA_IN_LOOP,
+
+  // Alloca argument is 0.
+  ALLOCA_ARG_IS_ZERO,
+
+  // Alloca call is unbounded.  That is, there is no controlling
+  // predicate for its argument.
+  ALLOCA_UNBOUNDED
+};
+
+// We have a few heuristics up our sleeve to determine if a call to
+// alloca() is within bounds.  Try them out and return the type of
+// alloca call this is based on its argument.
+//
+// Given a known argument (ARG) to alloca() and an EDGE (E)
+// calculating said argument, verify that the last statement in the BB
+// in E->SRC is a gate comparing ARG to an acceptable bound for
+// alloca().  See examples below.
+//
+// MAX_SIZE is WARN_ALLOCA= adjusted for VLAs.  It is the maximum size
+// in bytes we allow for arg.
+//
+// If the alloca bound is determined to be too large, ASSUMED_LIMIT is
+// set to the bound used to determine this.  ASSUMED_LIMIT is only set
+// for ALLOCA_BOUND_MAYBE_LARGE and ALLOCA_BOUND_DEFINITELY_LARGE.
+//
+// Returns the alloca type.
+
+static enum alloca_type
+alloca_call_type_by_arg (tree arg, edge e, unsigned max_size,
+			 wide_int *assumed_limit)
+{
+  // All the tests bellow depend on the jump being on the TRUE path.
+  if (!(e->flags & EDGE_TRUE_VALUE))
+    return ALLOCA_UNBOUNDED;
+
+  basic_block bb = e->src;
+  gimple_stmt_iterator gsi = gsi_last_bb (bb);
+  gimple *last = gsi_stmt (gsi);
+  if (!last || gimple_code (last) != GIMPLE_COND)
+    return ALLOCA_UNBOUNDED;
+
+  /* Check for:
+     if (ARG <= N)
+       goto <bb 3>;
+      else
+        goto <bb 4>;
+      <bb 3>:
+      alloca(ARG);
+  */
+  if (gimple_cond_code (last) == LE_EXPR
+      && gimple_cond_lhs (last) == arg)
+    {
+      if (TREE_CODE (gimple_cond_rhs (last)) == INTEGER_CST)
+	{
+	  tree rhs = gimple_cond_rhs (last);
+	  if (tree_to_uhwi (rhs) > max_size)
+	    {
+	      *assumed_limit = rhs;
+	      return ALLOCA_BOUND_MAYBE_LARGE;
+	    }
+	  return ALLOCA_OK;
+	}
+      else
+	return ALLOCA_BOUND_UNKNOWN;
+    }
+
+  /* Check for:
+     if (arg .cond. LIMIT) -or- if (LIMIT .cond. arg)
+       alloca(arg);
+
+     Where LIMIT has a bound of unknown range.  */
+  tree limit = NULL;
+  if (gimple_cond_lhs (last) == arg)
+    limit = gimple_cond_rhs (last);
+  else if (gimple_cond_rhs (last) == arg)
+    limit = gimple_cond_lhs (last);
+  if (limit && TREE_CODE (limit) == SSA_NAME)
+    {
+      wide_int min, max;
+      value_range_type range_type = get_range_info (limit, &min, &max);
+      if (range_type == VR_UNDEFINED || range_type == VR_VARYING)
+	return ALLOCA_BOUND_UNKNOWN;
+      // FIXME: We could try harder here and handle a possible range
+      // or anti-range.  Hopefully the upcoming changes to range info
+      // will give us finer grained info, and we can avoid somersaults
+      // here.
+    }
+
+  return ALLOCA_UNBOUNDED;
+}
+
+// Return TRUE if SSA's definition is a cast from a signed type.
+// If so, set *INVALID_CASTED_TYPE to the signed type.
+
+static bool
+cast_from_signed_p (tree ssa, tree *invalid_casted_type)
+{
+  gimple *def = SSA_NAME_DEF_STMT (ssa);
+  if (def
+      && !gimple_nop_p (def)
+      && gimple_assign_cast_p (def)
+      && !TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (def))))
+    {
+      *invalid_casted_type = TREE_TYPE (gimple_assign_rhs1 (def));
+      return true;
+    }
+  return false;
+}
+
+// Return TURE if X has a maximum range of MAX, basically covering the
+// entire domain, in which case it's no range at all.
+
+static bool
+is_max (tree x, wide_int max)
+{
+  return wi::max_value (TREE_TYPE (x)) == max;
+}
+
+// Analyze the alloca call in STMT and return an `enum alloca_type'
+// explaining what type of alloca it is.  IS_VLA is set if the alloca
+// call is really a BUILT_IN_ALLOCA_WITH_ALIGN, signifying a VLA.
+//
+// If the alloca bound is determined to be too large, ASSUMED_LIMIT is
+// set to the bound used to determine this.  ASSUMED_LIMIT is only set
+// for ALLOCA_BOUND_MAYBE_LARGE and ALLOCA_BOUND_DEFINITELY_LARGE.
+//
+// If the alloca call may be too large because of a cast from a signed
+// type to an unsigned type, set *INVALID_CASTED_TYPE to the
+// problematic signed type.
+
+static enum alloca_type
+alloca_call_type (gimple *stmt, bool is_vla, wide_int *assumed_limit,
+		  tree *invalid_casted_type)
+{
+  gcc_assert (gimple_alloca_call_p (stmt));
+  tree len = gimple_call_arg (stmt, 0);
+  enum alloca_type w = ALLOCA_UNBOUNDED;
+  wide_int min, max;
+
+  gcc_assert (!is_vla || warn_vla_limit > 0);
+  gcc_assert (is_vla || warn_alloca_limit > 0);
+
+  // Adjust warn_alloca_max_size for VLAs, by taking the underlying
+  // type into account.
+  unsigned HOST_WIDE_INT max_size;
+  if (is_vla)
+    max_size = (unsigned HOST_WIDE_INT) warn_vla_limit;
+  else
+    max_size = (unsigned HOST_WIDE_INT) warn_alloca_limit;
+
+  // Check for the obviously bounded case.
+  if (TREE_CODE (len) == INTEGER_CST)
+    {
+      if (tree_to_uhwi (len) > max_size)
+	{
+	  *assumed_limit = len;
+	  return ALLOCA_BOUND_DEFINITELY_LARGE;
+	}
+      if (integer_zerop (len))
+	return ALLOCA_ARG_IS_ZERO;
+      w = ALLOCA_OK;
+    }
+  else if (TREE_CODE (len) != SSA_NAME)
+    return ALLOCA_UNBOUNDED;
+  // Check the range info if available.
+  else
+    {
+      if (value_range_type range_type = get_range_info (len, &min, &max))
+	{
+	  if (range_type == VR_RANGE)
+	    {
+	      if (wi::leu_p (max, max_size))
+		w = ALLOCA_OK;
+	      else if (is_max (len, max))
+		{
+		  // A cast may have created a range we don't care
+		  // about.  For instance, a cast from 16-bit to
+		  // 32-bit creates a range of 0..65535, even if there
+		  // is not really a determinable range in the
+		  // underlying code.  In this case, look through the
+		  // cast at the original argument, and fall through
+		  // to look at other alternatives.
+		  gimple *def = SSA_NAME_DEF_STMT (len);
+		  if (gimple_assign_cast_p (def))
+		    len = gimple_assign_rhs1 (def);
+		}
+	      else
+		{
+		  /* If `len' is merely a cast that is being
+		     calculated right before the call to alloca, look
+		     at the range for the original value.
+
+		     This avoids the cast creating a range where the
+		     original expression did not have a range:
+
+		     # RANGE [0, 18446744073709551615] NONZERO 4294967295
+		     _2 = (long unsigned int) n_7(D);
+		     p_9 = __builtin_alloca (_2);
+
+		     The correct thing would've been for the user to
+		     use size_t, which in the case above would've been
+		     'long unsigned int', and everything would've
+		     worked.  But we have to catch cases where the
+		     user is using some other compatible type for the
+		     call argument to alloca (say unsigned short).  */
+		  gimple *def = SSA_NAME_DEF_STMT (len);
+		  if (gimple_assign_cast_p (def))
+		    {
+		      len = gimple_assign_rhs1 (def);
+		      range_type = get_range_info (len, &min, &max);
+		    }
+
+		  if (range_type != VR_VARYING && is_max (len, max))
+		    {
+		      // Treat a max of the entire domain as if it had no
+		      // range info, and fall through the try other
+		      // alternatives.
+		    }
+		  else
+		    {
+		      *assumed_limit = max;
+		      return ALLOCA_BOUND_MAYBE_LARGE;
+		    }
+		}
+	    }
+	  else if (range_type == VR_ANTI_RANGE)
+	    {
+	      // There may be some wrapping around going on.  Catch it
+	      // with this heuristic.  Hopefully, this VR_ANTI_RANGE
+	      // nonsense will go away, and we won't have to catch the
+	      // sign conversion problems with this crap.
+	      if (cast_from_signed_p (len, invalid_casted_type))
+		return ALLOCA_CAST_FROM_SIGNED;
+
+	      // Fall thru and try other things.
+	    }
+	  else if (range_type == VR_VARYING)
+	    {
+	      // No easily determined range.  Try other things.
+	    }
+	}
+    }
+
+  // If we couldn't find anything, try a few heuristics for things we
+  // can easily determine.  Check these misc cases but only accept
+  // them if all predecessors have a known bound.
+  basic_block bb = gimple_bb (stmt);
+  if (w == ALLOCA_UNBOUNDED)
+    {
+      w = ALLOCA_OK;
+      for (unsigned ix = 0; ix < EDGE_COUNT (bb->preds); ix++)
+	{
+	  enum alloca_type w
+	    = alloca_call_type_by_arg (len, EDGE_PRED (bb, ix), max_size,
+				       assumed_limit);
+	  if (w != ALLOCA_OK)
+	    return w;
+	}
+    }
+
+  return w;
+}
+
+// Return TRUE if the alloca call in STMT is in a loop, otherwise
+// return FALSE. As an exception, ignore alloca calls for VLAs that
+// occur in a loop since those will be cleaned up when they go out of
+// scope.
+
+static bool
+in_loop_p (bool is_vla, gimple *stmt)
+{
+  basic_block bb = gimple_bb (stmt);
+  if (bb->loop_father
+      // ?? Functions with no loops get a loop_father?  I
+      // don't get it.  The following conditional seems to do
+      // the trick to exclude such nonsense.
+      && bb->loop_father->header != ENTRY_BLOCK_PTR_FOR_FN (cfun))
+    {
+      // Do not warn on VLAs occurring in a loop, since VLAs are
+      // guaranteed to be cleaned up when they go out of scope.
+      // That is, there is a corresponding __builtin_stack_restore
+      // at the end of the scope in which the VLA occurs.
+      tree fndecl = gimple_call_fn (stmt);
+      while (TREE_CODE (fndecl) == ADDR_EXPR)
+	fndecl = TREE_OPERAND (fndecl, 0);
+      if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+	  && is_vla
+	  && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA_WITH_ALIGN)
+	return false;
+
+      return true;
+    }
+  return false;
+}
+
+unsigned int
+pass_walloca::execute (function *fun)
+{
+  basic_block bb;
+  FOR_EACH_BB_FN (bb, fun)
+    {
+      for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);
+	   gsi_next (&si))
+	{
+	  gimple *stmt = gsi_stmt (si);
+	  location_t loc = gimple_location (stmt);
+
+	  if (!gimple_alloca_call_p (stmt))
+	    continue;
+	  gcc_assert (gimple_call_num_args (stmt) >= 1);
+
+	  bool is_vla = gimple_alloca_call_p (stmt)
+	    && gimple_call_alloca_for_var_p (as_a <gcall *> (stmt));
+
+	  // Strict mode whining for VLAs is handled by the front-end,
+	  // so we can safely ignore this case.  Also, ignore VLAs if
+	  // the user doesn't care about them.
+	  if (is_vla
+	      && (warn_vla > 0 || !warn_vla_limit))
+	    continue;
+
+	  if (!is_vla && (warn_alloca || !warn_alloca_limit))
+	    {
+	      if (warn_alloca)
+		warning_at (loc, OPT_Walloca, "use of %<alloca%>");
+	      continue;
+	    }
+
+	  wide_int assumed_limit
+	    = wi::to_wide (integer_zero_node,
+			   TYPE_PRECISION (size_type_node));
+	  tree invalid_casted_type = NULL;
+	  enum alloca_type w = alloca_call_type (stmt, is_vla, &assumed_limit,
+						 &invalid_casted_type);
+
+	  // Even if we think the alloca call is OK, make sure it's
+	  // not in a loop.
+	  if (w == ALLOCA_OK && in_loop_p (is_vla, stmt))
+	    w = ALLOCA_IN_LOOP;
+
+	  enum opt_code wcode
+	    = is_vla ? OPT_Wvla_larger_than_ : OPT_Walloca_larger_than_;
+	  char buff[WIDE_INT_MAX_PRECISION / 4 + 4];
+	  switch (w)
+	    {
+	    case ALLOCA_OK:
+	      break;
+	    case ALLOCA_BOUND_MAYBE_LARGE:
+	      gcc_assert (assumed_limit != 0);
+	      if (warning_at (loc, wcode,
+			      is_vla ? "argument to variable-length array "
+			      "may be too large"
+			      : "argument to %<alloca%> may be too large"))
+		{
+		  print_decu (assumed_limit, buff);
+		  inform (loc, "limit is %u bytes, but argument "
+			  "may be as large as %s",
+			  is_vla ? warn_vla_limit : warn_alloca_limit, buff);
+		}
+	      break;
+	    case ALLOCA_BOUND_DEFINITELY_LARGE:
+	      gcc_assert (assumed_limit != 0);
+	      if (warning_at (loc, wcode,
+			      is_vla ? "argument to variable-length array "
+			      "is too large"
+			      : "argument to %<alloca%> is too large"))
+		{
+		  print_decu (assumed_limit, buff);
+		  inform (loc, "limit is %u bytes, but argument is %s",
+			  is_vla ? warn_vla_limit : warn_alloca_limit, buff);
+		}
+	      break;
+	    case ALLOCA_BOUND_UNKNOWN:
+	      warning_at (loc, wcode,
+			  is_vla ? "variable-length array bound is unknown"
+			  : "%<alloca%> bound is unknown");
+	      break;
+	    case ALLOCA_UNBOUNDED:
+	      warning_at (loc, wcode,
+			  is_vla ? "unbounded use of variable-length array"
+			  : "unbounded use of %<alloca%>");
+	      break;
+	    case ALLOCA_IN_LOOP:
+	      warning_at (loc, wcode,
+			  is_vla ? "use of variable-length array "
+			  "within a loop"
+			  : "use of %<alloca%> within a loop");
+	      break;
+	    case ALLOCA_CAST_FROM_SIGNED:
+	      gcc_assert (invalid_casted_type != NULL_TREE);
+	      warning_at (loc, wcode,
+			  is_vla ? "argument to variable-length array "
+			  "may be too large due to "
+			  "conversion from %qT to %qT"
+			  : "argument to %<alloca%> may be too large due to "
+			  "conversion from %qT to %qT",
+			  invalid_casted_type, size_type_node);
+	      break;
+	    case ALLOCA_ARG_IS_ZERO:
+	      warning_at (loc, wcode,
+			  is_vla ? "argument to variable-length array is zero"
+			  : "argument to %<alloca%> is zero");
+	      break;
+	    default:
+	      gcc_unreachable ();
+	    }
+	}
+    }
+  return 0;
+}
+
+gimple_opt_pass *
+make_pass_walloca (gcc::context *ctxt)
+{
+  return new pass_walloca (ctxt);
+}
diff --git a/gcc/opts.c b/gcc/opts.c
index e80331f..7cdb4bf 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -743,6 +743,20 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
   if (opts->x_flag_tm && opts->x_flag_non_call_exceptions)
     sorry ("transactional memory is not supported with non-call exceptions");
 
+  // -Walloca-larger-than=N needs range info which is only available at -O2.
+  if (opts->x_warn_alloca_limit > 0 && opts->x_optimize < 2)
+    {
+      warning_at (loc, 0, "-Walloca-larger-than=N ignored without -O2");
+      opts->x_warn_alloca_limit = 0;
+    }
+
+  // -Wvla-larger-than= needs range info which is only available at -O2.
+  if (opts->x_warn_vla_limit > 0 && opts->x_optimize < 2)
+    {
+      warning_at (loc, 0, "-Wvla-larger-than= ignored without -O2");
+      opts->x_warn_vla_limit = 0;
+    }
+
   /* Unless the user has asked for section anchors, we disable toplevel
      reordering at -O0 to disable transformations that might be surprising
      to end users and to get -fno-toplevel-reorder tested.  */
diff --git a/gcc/passes.def b/gcc/passes.def
index 3647e90..591add2 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3.  If not see
   NEXT_PASS (pass_warn_function_return);
   NEXT_PASS (pass_expand_omp);
   NEXT_PASS (pass_build_cgraph_edges);
+  NEXT_PASS (pass_walloca, /*strict_mode_p=*/true);
   TERMINATE_PASS_LIST (all_lowering_passes)
 
   /* Interprocedural optimization passes.  */
@@ -303,6 +304,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_simduid_cleanup);
       NEXT_PASS (pass_lower_vector_ssa);
       NEXT_PASS (pass_cse_reciprocals);
+      NEXT_PASS (pass_walloca, /*strict_mode_p=*/false);
       NEXT_PASS (pass_reassoc, false /* insert_powi_p */);
       NEXT_PASS (pass_strength_reduction);
       NEXT_PASS (pass_split_paths);
diff --git a/gcc/testsuite/gcc.dg/Walloca-1.c b/gcc/testsuite/gcc.dg/Walloca-1.c
new file mode 100644
index 0000000..34a20c3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-1.c
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=2000 -O2" } */
+
+#define alloca __builtin_alloca
+
+typedef __SIZE_TYPE__ size_t;
+extern size_t strlen(const char *);
+
+extern void useit (char *);
+
+int num;
+
+void foo1 (size_t len, size_t len2, size_t len3)
+{
+  int i;
+
+  for (i=0; i < 123; ++i)
+    {
+      char *s = alloca (566);	/* { dg-warning "'alloca' within a loop" } */
+      useit (s);
+    }
+
+  char *s = alloca (123);
+  useit (s);			// OK, constant argument to alloca
+
+  s = alloca (num);		// { dg-warning "large due to conversion" }
+  useit (s);
+
+  s = alloca(90000);		/* { dg-warning "is too large" } */
+  useit (s);
+
+  if (len < 2000)
+    {
+      s = alloca(len);		// OK, bounded
+      useit (s);
+    }
+
+  if (len + len2 < 2000)	// OK, bounded
+    {
+      s = alloca(len + len2);
+      useit (s);
+    }
+
+  if (len3 <= 2001)
+    {
+      s = alloca(len3);		/* { dg-warning "may be too large" } */
+      useit(s);
+    }
+}
+
+void foo2 (__SIZE_TYPE__ len)
+{
+  // Test that a direct call to __builtin_alloca_with_align is not confused
+  // with a VLA.
+  void *p = __builtin_alloca_with_align (len, 8); // { dg-warning "unbounded use of 'alloca'" }
+  useit (p);
+}
+
+void foo3 (unsigned char a)
+{
+  if (a == 0)
+    useit (__builtin_alloca (a)); // { dg-warning "argument to 'alloca' is zero" }
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-2.c b/gcc/testsuite/gcc.dg/Walloca-2.c
new file mode 100644
index 0000000..284b34e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-2.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=2000 -O2" } */
+
+void f (void *);
+
+void
+g1 (int n)
+{
+  void *p;
+  if (n > 0 && n < 2000)
+    p = __builtin_alloca (n);
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
+
+void
+g2 (int n)
+{
+  void *p;
+  if (n < 2000)
+    p = __builtin_alloca (n); // { dg-warning "large due to conversion" }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
+
+void
+g3 (int n)
+{
+  void *p;
+  if (n > 0 && n < 3000)
+    {
+      p = __builtin_alloca (n); // { dg-warning "'alloca' may be too large" }
+      // { dg-message "note:.*argument may be as large as 2999" "note" { target *-*-* } 34 }
+    }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-3.c b/gcc/testsuite/gcc.dg/Walloca-3.c
new file mode 100644
index 0000000..5345197
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-3.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=2000 -O2" } */
+
+void f (void *);
+
+__SIZE_TYPE__ LIMIT;
+
+// Warn when there is an alloca bound, but it is an unknown bound.
+
+void
+g1 (__SIZE_TYPE__ n)
+{
+  void *p;
+  if (n < LIMIT)
+    p = __builtin_alloca (n); // { dg-warning "'alloca' bound is unknown" }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
+
+// Similar to the above, but do not get confused by the upcast.
+
+unsigned short SHORT_LIMIT;
+void
+g2 (unsigned short n)
+{
+  void *p;
+  if (n < SHORT_LIMIT)
+    p = __builtin_alloca (n); // { dg-warning "'alloca' bound is unknown" }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-4.c b/gcc/testsuite/gcc.dg/Walloca-4.c
new file mode 100644
index 0000000..d96cc4e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-4.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=5000 -O2" } */
+/* { dg-xfail-if "Currently broken but Andrew's work should fix this" { *-*-* } } */
+
+// Should be another variant of Walloca-7.c.
+// This should not warn, as we have a known bound within limits.
+
+ char *
+ _i18n_number_rewrite (char *w, char *rear_ptr)
+{
+
+  char *src;
+ _Bool 
+      use_alloca = (((rear_ptr - w) * sizeof (char)) < 4096U);
+ if (use_alloca)
+    src = (char *) __builtin_alloca ((rear_ptr - w) * sizeof (char));
+  else
+    src = (char *) __builtin_malloc ((rear_ptr - w) * sizeof (char));
+  return src;
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-5.c b/gcc/testsuite/gcc.dg/Walloca-5.c
new file mode 100644
index 0000000..5ed1171
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-5.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=123 -O2" } */
+/* { dg-xfail-if "Currently broken but Andrew's work should fix this" { *-*-* } } */
+
+/* The argument to alloca ends up having a range of 0..MAXINT(32bits),
+   so we think we have a range because of the upcast.  Consequently,
+   we warn with "alloca may be too large", but we should technically
+   warn with "unbounded use of alloca".
+
+   We currently drill through casts to figure this stuff out, but we
+   get confused because it's not just a cast.  It's a cast, plus a
+   multiply.
+
+   <bb 2>:
+  # RANGE [0, 4294967295] NONZERO 4294967295
+  _1 = (long unsigned int) something_4(D);
+  # RANGE [0, 34359738360] NONZERO 34359738360
+  _2 = _1 * 8;
+  _3 = __builtin_alloca (_2);
+
+  I don't know whether it's even worth such fine-grained warnings.
+  Perhaps we should generically warn everywhere with "alloca may be
+  too large".
+
+  I'm hoping that this particular case will be easier to diagnose with
+  Andrew's work.  */
+
+void useit(void *);
+void foobar(unsigned int something)
+{
+  useit(__builtin_alloca (something * sizeof (const char *))); // { dg-warning "unbounded use of alloca" "" { xfail *-*-* } }
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-6.c b/gcc/testsuite/gcc.dg/Walloca-6.c
new file mode 100644
index 0000000..b4d8d41
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-6.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=256 -O2" } */
+/* { dg-xfail-if "Currently broken but Andrew's work should fix this" { *-*-* } } */
+
+void f (void*);
+void g (__SIZE_TYPE__ n)
+{
+  // No warning on this case.  Range is easily determinable.
+  if (n > 0 && n < 256)
+    f (__builtin_alloca (n));
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-7.c b/gcc/testsuite/gcc.dg/Walloca-7.c
new file mode 100644
index 0000000..d6581a5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-7.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca -O0" } */
+
+extern void f(void *);
+
+void foo(void)
+{
+  // Test that strict -Walloca works even without optimization.
+  f (__builtin_alloca(500)); // { dg-warning "use of 'alloca'" }
+}
+
+void bar(void)
+{
+  // Test that we warn on alloca() calls, not just __builtin_alloca calls.
+  extern void *alloca(__SIZE_TYPE__);
+  f (alloca (123)); // { dg-warning "use of 'alloca'" }
+}
diff --git a/gcc/testsuite/gcc.dg/Wvla-1.c b/gcc/testsuite/gcc.dg/Wvla-1.c
new file mode 100644
index 0000000..384c930
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wvla-1.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-Wvla-larger-than=100 -O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern void useit (char *);
+
+int num;
+
+void test_vlas (size_t num)
+{
+  char str2[num];		/* { dg-warning "unbounded use" } */
+  useit(str2);
+
+  num = 98;
+  for (int i=0; i < 1234; ++i) {
+    char str[num];	        // OK, VLA in a loop, but it is a
+				// known size *AND* the compiler takes
+				// care of cleaning up between
+				// iterations with
+				// __builtin_stack_restore.
+    useit(str);
+  }
+}
diff --git a/gcc/testsuite/gcc.dg/Wvla-2.c b/gcc/testsuite/gcc.dg/Wvla-2.c
new file mode 100644
index 0000000..96814dc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wvla-2.c
@@ -0,0 +1,70 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target stdint_types } */
+/* { dg-options "-O2 -Wvla-larger-than=40" } */
+
+#include <stdint.h>
+
+void f0 (void *);
+void
+f1 (__SIZE_TYPE__ a)
+{
+  if (a <= 10)
+    {
+      // 10 * 4 bytes = 40: OK!
+      uint32_t x[a];
+      f0 (x);
+    }
+}
+
+void
+f2 (__SIZE_TYPE__ a)
+{
+  if (a <= 11)
+    {
+      // 11 * 4 bytes = 44: Not OK.
+      uint32_t x[a]; // { dg-warning "array may be too large" }
+      // { dg-message "note:.*argument may be as large as 44" "note" { target *-*-* } 25 }
+      f0 (x);
+    }
+}
+
+void
+f3 (__SIZE_TYPE__ a, __SIZE_TYPE__ b)
+{
+  if (a <= 5 && b <= 3)
+    {
+      // 5 * 3 * 4 bytes = 60: Not OK.
+      uint32_t x[a][b]; // { dg-warning "array may be too large" }
+      f0 (x);
+    }
+}
+
+void
+f4 (__SIZE_TYPE__ a, __SIZE_TYPE__ b)
+{
+  if (a <= 5 && b <= 2)
+    {
+      // 5 * 2 * 4 bytes = 40 bytes: OK!
+      uint32_t x[a][b];
+      f0 (x);
+    }
+}
+
+void
+f5 (__SIZE_TYPE__ len)
+{
+  // Test that a direct call to __builtin_alloca_with_align is not
+  // confused with a VLA.
+  void *p = __builtin_alloca_with_align (len, 8);
+  f0 (p);
+}
+
+void
+f6 (unsigned stuff)
+{
+  int n = 7000;
+  do {
+    char a[n]; // { dg-warning "variable-length array is too large" }
+    f0 (a);
+  } while (stuff--);
+}
diff --git a/gcc/testsuite/gcc.dg/Wvla-3.c b/gcc/testsuite/gcc.dg/Wvla-3.c
new file mode 100644
index 0000000..5124476
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wvla-3.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca -O2" } */
+
+// Make sure we don't warn on VLA with -Walloca.
+
+void f (void*);
+
+void h1 (unsigned n)
+{
+  int a [n];
+  f (a);
+}
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 36299a6..57b61f4 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -469,6 +469,7 @@ extern simple_ipa_opt_pass *make_pass_ipa_oacc (gcc::context *ctxt);
 extern simple_ipa_opt_pass *make_pass_ipa_oacc_kernels (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_gen_hsail (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_warn_nonnull_compare (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_walloca (gcc::context *ctxt);
 
 /* IPA Passes */
 extern simple_ipa_opt_pass *make_pass_ipa_lower_emutls (gcc::context *ctxt);

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-17 15:53     ` Manuel López-Ibáñez
  2016-07-18 10:10       ` Aldy Hernandez
@ 2016-07-19 17:47       ` Jeff Law
  2016-07-19 18:07         ` Manuel López-Ibáñez
  2016-07-19 19:05         ` Aldy Hernandez
  1 sibling, 2 replies; 26+ messages in thread
From: Jeff Law @ 2016-07-19 17:47 UTC (permalink / raw)
  To: Manuel López-Ibáñez, Aldy Hernandez, Martin Sebor,
	gcc-patches, Martin Sebor
  Cc: Andrew MacLeod

On 07/17/2016 09:52 AM, Manuel López-Ibáñez wrote:
> +  if (is_vla)
> +    gcc_assert (warn_vla_limit > 0);
> +  if (!is_vla)
> +    gcc_assert (warn_alloca_limit > 0);
>
> if-else ? Or perhaps:
Shouldn't really matter, except perhaps in a -O0 compilation.  Though I 
think else-if makes it slightly clearer.

>
> gcc_assert (!is_vla || warn_vla_limit > 0);
> gcc_assert (is_vla || warn_alloca_limit > 0);
Would be acceptable as well.  I think any of the 3 is fine and leave it 
to Aldy's discretion which to use.

Jeff

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-19 11:03           ` Aldy Hernandez
@ 2016-07-19 17:54             ` Jeff Law
  2016-07-19 19:06               ` Aldy Hernandez
  2016-08-01 20:35             ` Joseph Myers
  1 sibling, 1 reply; 26+ messages in thread
From: Jeff Law @ 2016-07-19 17:54 UTC (permalink / raw)
  To: Aldy Hernandez, Martin Sebor, gcc-patches, Martin Sebor; +Cc: Andrew MacLeod

On 07/19/2016 05:03 AM, Aldy Hernandez wrote:
>> (Same thing with alloca).  There should be no warning for VLAs,
>> and for alloca, the warning should say "use of variable-length
>> array within a loop."  The VRP dump suggests the range information
>> is available within the loop.  Is the get_range_info() function
>> not returning the corresponding bounds?
>
> This is a false positive, but there's little we can do with the current
> range infrastructure.  The range information becomes less precise the
> further down the optimization pipeline we get.  So, even though as far
> as *.c.126t.crited1, we still see appropriate range information:
[ ... ]
So I think we can live with the false positive as an XFAIL while we wait 
for improved infrastructure.

I will note that you could use a two-stage approach to help with this 
kind of issue.  You note the set of potential large allocations early 
(before PRE or anyone else messes it up).  Then you allow the other 
optimizers to run, then go back and recheck the allocations after the 
last optimizer pass.  You end up with

flagged early  && flagged late --> warn
flagged early && ! flagged late -> optimization eliminated the false 
positive (which you can optionally issue a diagnostic for)
! flagged early -- never warn

I don't think you strictly need it here, but it's a way to approach some 
of these problems where you want to run a warning pass late (to allow 
the optimizers to eliminate false positives).

jeff

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-19 17:47       ` Jeff Law
@ 2016-07-19 18:07         ` Manuel López-Ibáñez
  2016-07-19 19:05         ` Aldy Hernandez
  1 sibling, 0 replies; 26+ messages in thread
From: Manuel López-Ibáñez @ 2016-07-19 18:07 UTC (permalink / raw)
  To: Jeff Law
  Cc: Aldy Hernandez, Martin Sebor, gcc-patches, Martin Sebor, Andrew MacLeod

On 19 July 2016 at 18:47, Jeff Law <law@redhat.com> wrote:
> On 07/17/2016 09:52 AM, Manuel López-Ibáñez wrote:
>>
>> +  if (is_vla)
>> +    gcc_assert (warn_vla_limit > 0);
>> +  if (!is_vla)
>> +    gcc_assert (warn_alloca_limit > 0);
>>
>> if-else ? Or perhaps:
>
> Shouldn't really matter, except perhaps in a -O0 compilation.  Though I
> think else-if makes it slightly clearer.

Of course, I mentioned it because of clarity. It was difficult to
distinguish !i versus (i in my screen and I had to stop to read it
again.

Cheers,

Manuel.

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-19 17:47       ` Jeff Law
  2016-07-19 18:07         ` Manuel López-Ibáñez
@ 2016-07-19 19:05         ` Aldy Hernandez
  1 sibling, 0 replies; 26+ messages in thread
From: Aldy Hernandez @ 2016-07-19 19:05 UTC (permalink / raw)
  To: Jeff Law, Manuel López-Ibáñez, Martin Sebor,
	gcc-patches, Martin Sebor
  Cc: Andrew MacLeod

On 07/19/2016 01:47 PM, Jeff Law wrote:
> On 07/17/2016 09:52 AM, Manuel López-Ibáñez wrote:
>> +  if (is_vla)
>> +    gcc_assert (warn_vla_limit > 0);
>> +  if (!is_vla)
>> +    gcc_assert (warn_alloca_limit > 0);
>>
>> if-else ? Or perhaps:
> Shouldn't really matter, except perhaps in a -O0 compilation.  Though I
> think else-if makes it slightly clearer.
>
>>

My preference would've been the if/else.  The missing else was an oversight.

However, since I really don't care, the last posted patch uses this:

 >> gcc_assert (!is_vla || warn_vla_limit > 0);
 >> gcc_assert (is_vla || warn_alloca_limit > 0);
 > Would be acceptable as well.  I think any of the 3 is fine and leave it
 > to Aldy's discretion which to use.
 >
 > Jeff

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-19 17:54             ` Jeff Law
@ 2016-07-19 19:06               ` Aldy Hernandez
  0 siblings, 0 replies; 26+ messages in thread
From: Aldy Hernandez @ 2016-07-19 19:06 UTC (permalink / raw)
  To: Jeff Law, Martin Sebor, gcc-patches, Martin Sebor; +Cc: Andrew MacLeod

On 07/19/2016 01:54 PM, Jeff Law wrote:
> On 07/19/2016 05:03 AM, Aldy Hernandez wrote:
>>> (Same thing with alloca).  There should be no warning for VLAs,
>>> and for alloca, the warning should say "use of variable-length
>>> array within a loop."  The VRP dump suggests the range information
>>> is available within the loop.  Is the get_range_info() function
>>> not returning the corresponding bounds?
>>
>> This is a false positive, but there's little we can do with the current
>> range infrastructure.  The range information becomes less precise the
>> further down the optimization pipeline we get.  So, even though as far
>> as *.c.126t.crited1, we still see appropriate range information:
> [ ... ]
> So I think we can live with the false positive as an XFAIL while we wait
> for improved infrastructure.
>
> I will note that you could use a two-stage approach to help with this
> kind of issue.  You note the set of potential large allocations early
> (before PRE or anyone else messes it up).  Then you allow the other
> optimizers to run, then go back and recheck the allocations after the
> last optimizer pass.  You end up with
>
> flagged early  && flagged late --> warn
> flagged early && ! flagged late -> optimization eliminated the false
> positive (which you can optionally issue a diagnostic for)
> ! flagged early -- never warn
>
> I don't think you strictly need it here, but it's a way to approach some
> of these problems where you want to run a warning pass late (to allow
> the optimizers to eliminate false positives).

If you feel strongly about this I can certainly do so, but until we get 
better range info, I'd prefer to work on other stuff ;-).

Let me know.

Aldy

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-07-19 11:03           ` Aldy Hernandez
  2016-07-19 17:54             ` Jeff Law
@ 2016-08-01 20:35             ` Joseph Myers
  2016-08-02 12:55               ` Aldy Hernandez
  1 sibling, 1 reply; 26+ messages in thread
From: Joseph Myers @ 2016-08-01 20:35 UTC (permalink / raw)
  To: Aldy Hernandez
  Cc: Martin Sebor, gcc-patches, Martin Sebor, Jeff Law, Andrew MacLeod

On Tue, 19 Jul 2016, Aldy Hernandez wrote:

> +      // Do not warn on VLAs occurring in a loop, since VLAs are
> +      // guaranteed to be cleaned up when they go out of scope.
> +      // That is, there is a corresponding __builtin_stack_restore
> +      // at the end of the scope in which the VLA occurs.

Given this ...

> +	    case ALLOCA_IN_LOOP:
> +	      warning_at (loc, wcode,
> +			  is_vla ? "use of variable-length array "
> +			  "within a loop"
> +			  : "use of %<alloca%> within a loop");
> +	      break;

 ... why is there a VLA case for this diagnostic at all?  I'd expect an 
assertion that only the alloca case can reach this diagnostic.

Also, if the format string for a diagnostic function is a ? : conditional 
expression you need to mark up each half with G_() so that both halves are 
properly extracted for translation.  This applies to lots of diagnostics 
in this patch.

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: RFA: new pass to warn on questionable uses of alloca() and VLAs
  2016-08-01 20:35             ` Joseph Myers
@ 2016-08-02 12:55               ` Aldy Hernandez
  0 siblings, 0 replies; 26+ messages in thread
From: Aldy Hernandez @ 2016-08-02 12:55 UTC (permalink / raw)
  To: Joseph Myers
  Cc: Martin Sebor, gcc-patches, Martin Sebor, Jeff Law, Andrew MacLeod

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

On 08/01/2016 04:35 PM, Joseph Myers wrote:
> On Tue, 19 Jul 2016, Aldy Hernandez wrote:
>
>> +      // Do not warn on VLAs occurring in a loop, since VLAs are
>> +      // guaranteed to be cleaned up when they go out of scope.
>> +      // That is, there is a corresponding __builtin_stack_restore
>> +      // at the end of the scope in which the VLA occurs.
>
> Given this ...
>
>> +	    case ALLOCA_IN_LOOP:
>> +	      warning_at (loc, wcode,
>> +			  is_vla ? "use of variable-length array "
>> +			  "within a loop"
>> +			  : "use of %<alloca%> within a loop");
>> +	      break;
>
>   ... why is there a VLA case for this diagnostic at all?  I'd expect an
> assertion that only the alloca case can reach this diagnostic.
>

Indeed.  Fixed.

> Also, if the format string for a diagnostic function is a ? : conditional
> expression you need to mark up each half with G_() so that both halves are
> properly extracted for translation.  This applies to lots of diagnostics
> in this patch.

Hugh, I didn't know about the G_() magic for marking format strings. 
Fixed everywhere.

OK?

[-- Attachment #2: curr --]
[-- Type: text/plain, Size: 34143 bytes --]

gcc/

	* Makefile.in (OBJS): Add gimple-ssa-warn-alloca.o.
	* passes.def: Add two instances of pass_walloca.
	* tree-pass.h (make_pass_walloca): New.
	* gimple-ssa-warn-walloca.c: New file.
	* doc/invoke.texi: Document -Walloca, -Walloca-larger-than=, and
	-Wvla-larger-than= options.

gcc/c-family/

	* c.opt (Walloca): New.
	(Walloca-larger-than=): New.
	(Wvla-larger-than=): New.

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 7a0160f..210153a 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1296,6 +1296,7 @@ OBJS = \
 	gimple-ssa-nonnull-compare.o \
 	gimple-ssa-split-paths.o \
 	gimple-ssa-strength-reduction.o \
+	gimple-ssa-warn-alloca.o \
 	gimple-streamer-in.o \
 	gimple-streamer-out.o \
 	gimple-walk.o \
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index c11e7e7..6e82fc8 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -376,6 +376,16 @@ c_common_handle_option (size_t scode, const char *arg, int value,
       cpp_opts->warn_num_sign_change = value;
       break;
 
+    case OPT_Walloca_larger_than_:
+      if (!value)
+	inform (loc, "-Walloca-larger-than=0 is meaningless");
+      break;
+
+    case OPT_Wvla_larger_than_:
+      if (!value)
+	inform (loc, "-Wvla-larger-than=0 is meaningless");
+      break;
+
     case OPT_Wunknown_pragmas:
       /* Set to greater than 1, so that even unknown pragmas in
 	 system headers will be warned about.  */
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index a5358ed..c9caffe 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -275,6 +275,16 @@ Wall
 C ObjC C++ ObjC++ Warning
 Enable most warning messages.
 
+Walloca
+C ObjC C++ ObjC++ Var(warn_alloca) Warning
+Warn on any use of alloca.
+
+Walloca-larger-than=
+C ObjC C++ ObjC++ Var(warn_alloca_limit) Warning Joined RejectNegative UInteger
+-Walloca-larger-than=<number> Warn on unbounded uses of
+alloca, and on bounded uses of alloca whose bound can be larger than
+<number> bytes.
+
 Warray-bounds
 LangEnabledBy(C ObjC C++ ObjC++,Wall)
 ; in common.opt
@@ -980,6 +990,12 @@ Wvla
 C ObjC C++ ObjC++ Var(warn_vla) Init(-1) Warning
 Warn if a variable length array is used.
 
+Wvla-larger-than=
+C ObjC C++ ObjC++ Var(warn_vla_limit) Warning Joined RejectNegative UInteger
+-Wvla-larger-than=<number> Warn on unbounded uses of variable-length arrays, and
+on bounded uses of variable-length arrays whose bound can be
+larger than <number> bytes.
+
 Wvolatile-register-var
 C ObjC C++ ObjC++ Var(warn_volatile_register_var) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
 Warn when a register variable is declared volatile.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 22001f9..82fb89e 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -255,6 +255,7 @@ Objective-C and Objective-C++ Dialects}.
 @gccoptlist{-fsyntax-only  -fmax-errors=@var{n}  -Wpedantic @gol
 -pedantic-errors @gol
 -w  -Wextra  -Wall  -Waddress  -Waggregate-return  @gol
+-Walloca -Walloca-larger-than=@var{n} @gol
 -Wno-aggressive-loop-optimizations -Warray-bounds -Warray-bounds=@var{n} @gol
 -Wno-attributes -Wbool-compare -Wno-builtin-macro-redefined @gol
 -Wc90-c99-compat -Wc99-c11-compat @gol
@@ -311,7 +312,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wunused-const-variable -Wunused-const-variable=@var{n} @gol
 -Wunused-but-set-parameter -Wunused-but-set-variable @gol
 -Wuseless-cast -Wvariadic-macros -Wvector-operation-performance @gol
--Wvla -Wvolatile-register-var  -Wwrite-strings @gol
+-Wvla -Wvla-larger-than=@var{n} -Wvolatile-register-var  -Wwrite-strings @gol
 -Wzero-as-null-pointer-constant -Whsa}
 
 @item C and Objective-C-only Warning Options
@@ -4666,6 +4667,61 @@ annotations.
 Warn about overriding virtual functions that are not marked with the override
 keyword.
 
+@item -Walloca
+@opindex Wno-alloca
+@opindex Walloca
+This option warns on all uses of @code{alloca} in the source.
+
+@item -Walloca-larger-than=@var{n}
+This option warns on calls to @code{alloca} that are not bounded by a
+controlling predicate limiting its size to @var{n} bytes, or calls to
+@code{alloca} where the bound is unknown.
+
+For example, a bounded case of @code{alloca} could be:
+
+@smallexample
+unsigned int n;
+...
+if (n <= 1000)
+  alloca (n);
+@end smallexample
+
+In the above example, passing @code{-Walloca=1000} would not issue a
+warning because the call to @code{alloca} is known to be at most 1000
+bytes.  However, if @code{-Walloca=500} was passed, the compiler would
+have emitted a warning.
+
+Unbounded uses, on the other hand, are uses of @code{alloca} with no
+controlling predicate verifying its size.  For example:
+
+@smallexample
+stuff ();
+alloca (n);
+@end smallexample
+
+If @code{-Walloca=500} was passed, the above would trigger a warning,
+but this time because of the lack of bounds checking.
+
+Note, that even seemingly correct code involving signed integers could
+cause a warning:
+
+@smallexample
+signed int n;
+...
+if (n < 500)
+  alloca (n);
+@end smallexample
+
+In the above example, @var{n} could be negative, causing a larger than
+expected argument to be implicitly casted into the @code{alloca} call.
+
+This option also warns when @code{alloca} is used in a loop.
+
+This warning is not enabled by @option{-Wall}, and is only active when
+@option{-ftree-vrp} is active (default for @option{-O2} and above).
+
+See also @option{-Wvla-larger-than=@var{n}}.
+
 @item -Warray-bounds
 @itemx -Warray-bounds=@var{n}
 @opindex Wno-array-bounds
@@ -5830,9 +5886,25 @@ moving from a moved-from object, this warning can be disabled.
 @item -Wvla
 @opindex Wvla
 @opindex Wno-vla
-Warn if variable length array is used in the code.
+Warn if a variable-length array is used in the code.
 @option{-Wno-vla} prevents the @option{-Wpedantic} warning of
-the variable length array.
+the variable-length array.
+
+@item -Wvla-larger-than=@var{n}
+If this option is used, the compiler will warn on uses of
+variable-length arrays where the size is either unbounded, or bounded
+by an argument that can be larger than @var{n} bytes.  This is similar
+to how @option{-Walloca-larger-than=@var{n}} works, but with
+variable-length arrays.
+
+Note that GCC may optimize small variable-length arrays of a known
+value into plain arrays, so this warning may not get triggered for
+such arrays.
+
+This warning is not enabled by @option{-Wall}, and is only active when
+@option{-ftree-vrp} is active (default for @option{-O2} and above).
+
+See also @option{-Walloca-larger-than=@var{n}}.
 
 @item -Wvolatile-register-var
 @opindex Wvolatile-register-var
diff --git a/gcc/gimple-ssa-warn-alloca.c b/gcc/gimple-ssa-warn-alloca.c
new file mode 100644
index 0000000..2be0ed2
--- /dev/null
+++ b/gcc/gimple-ssa-warn-alloca.c
@@ -0,0 +1,517 @@
+/* Warn on problematic uses of alloca and variable length arrays.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Contributed by Aldy Hernandez <aldyh@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+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/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "ssa.h"
+#include "gimple-pretty-print.h"
+#include "diagnostic-core.h"
+#include "fold-const.h"
+#include "gimple-iterator.h"
+#include "tree-ssa.h"
+#include "params.h"
+#include "tree-cfg.h"
+#include "calls.h"
+#include "cfgloop.h"
+#include "intl.h"
+
+const pass_data pass_data_walloca = {
+  GIMPLE_PASS,
+  "walloca",
+  OPTGROUP_NONE,
+  TV_NONE,
+  PROP_cfg, // properties_required
+  0,	    // properties_provided
+  0,	    // properties_destroyed
+  0,	    // properties_start
+  0,	    // properties_finish
+};
+
+class pass_walloca : public gimple_opt_pass
+{
+public:
+  pass_walloca (gcc::context *ctxt)
+    : gimple_opt_pass(pass_data_walloca, ctxt), first_time_p (false)
+  {}
+  opt_pass *clone () { return new pass_walloca (m_ctxt); }
+  void set_pass_param (unsigned int n, bool param)
+    {
+      gcc_assert (n == 0);
+      first_time_p = param;
+    }
+  virtual bool gate (function *);
+  virtual unsigned int execute (function *);
+
+ private:
+  // Set to TRUE the first time we run this pass on a function.
+  bool first_time_p;
+};
+
+bool
+pass_walloca::gate (function *fun ATTRIBUTE_UNUSED)
+{
+  // The first time this pass is called, it is called before
+  // optimizations have been run and range information is unavailable,
+  // so we can only perform strict alloca checking.
+  if (first_time_p)
+    return warn_alloca != 0;
+
+  return warn_alloca_limit > 0 || warn_vla_limit > 0;
+}
+
+// Possible problematic uses of alloca.
+enum alloca_type {
+  // Alloca argument is within known bounds that are appropriate.
+  ALLOCA_OK,
+
+  // Alloca argument is KNOWN to have a value that is too large.
+  ALLOCA_BOUND_DEFINITELY_LARGE,
+
+  // Alloca argument may be too large.
+  ALLOCA_BOUND_MAYBE_LARGE,
+
+  // Alloca argument is bounded but of an indeterminate size.
+  ALLOCA_BOUND_UNKNOWN,
+
+  // Alloca argument was casted from a signed integer.
+  ALLOCA_CAST_FROM_SIGNED,
+
+  // Alloca appears in a loop.
+  ALLOCA_IN_LOOP,
+
+  // Alloca argument is 0.
+  ALLOCA_ARG_IS_ZERO,
+
+  // Alloca call is unbounded.  That is, there is no controlling
+  // predicate for its argument.
+  ALLOCA_UNBOUNDED
+};
+
+// We have a few heuristics up our sleeve to determine if a call to
+// alloca() is within bounds.  Try them out and return the type of
+// alloca call this is based on its argument.
+//
+// Given a known argument (ARG) to alloca() and an EDGE (E)
+// calculating said argument, verify that the last statement in the BB
+// in E->SRC is a gate comparing ARG to an acceptable bound for
+// alloca().  See examples below.
+//
+// MAX_SIZE is WARN_ALLOCA= adjusted for VLAs.  It is the maximum size
+// in bytes we allow for arg.
+//
+// If the alloca bound is determined to be too large, ASSUMED_LIMIT is
+// set to the bound used to determine this.  ASSUMED_LIMIT is only set
+// for ALLOCA_BOUND_MAYBE_LARGE and ALLOCA_BOUND_DEFINITELY_LARGE.
+//
+// Returns the alloca type.
+
+static enum alloca_type
+alloca_call_type_by_arg (tree arg, edge e, unsigned max_size,
+			 wide_int *assumed_limit)
+{
+  // All the tests bellow depend on the jump being on the TRUE path.
+  if (!(e->flags & EDGE_TRUE_VALUE))
+    return ALLOCA_UNBOUNDED;
+
+  basic_block bb = e->src;
+  gimple_stmt_iterator gsi = gsi_last_bb (bb);
+  gimple *last = gsi_stmt (gsi);
+  if (!last || gimple_code (last) != GIMPLE_COND)
+    return ALLOCA_UNBOUNDED;
+
+  /* Check for:
+     if (ARG <= N)
+       goto <bb 3>;
+      else
+        goto <bb 4>;
+      <bb 3>:
+      alloca(ARG);
+  */
+  if (gimple_cond_code (last) == LE_EXPR
+      && gimple_cond_lhs (last) == arg)
+    {
+      if (TREE_CODE (gimple_cond_rhs (last)) == INTEGER_CST)
+	{
+	  tree rhs = gimple_cond_rhs (last);
+	  if (tree_to_uhwi (rhs) > max_size)
+	    {
+	      *assumed_limit = rhs;
+	      return ALLOCA_BOUND_MAYBE_LARGE;
+	    }
+	  return ALLOCA_OK;
+	}
+      else
+	return ALLOCA_BOUND_UNKNOWN;
+    }
+
+  /* Check for:
+     if (arg .cond. LIMIT) -or- if (LIMIT .cond. arg)
+       alloca(arg);
+
+     Where LIMIT has a bound of unknown range.  */
+  tree limit = NULL;
+  if (gimple_cond_lhs (last) == arg)
+    limit = gimple_cond_rhs (last);
+  else if (gimple_cond_rhs (last) == arg)
+    limit = gimple_cond_lhs (last);
+  if (limit && TREE_CODE (limit) == SSA_NAME)
+    {
+      wide_int min, max;
+      value_range_type range_type = get_range_info (limit, &min, &max);
+      if (range_type == VR_UNDEFINED || range_type == VR_VARYING)
+	return ALLOCA_BOUND_UNKNOWN;
+      // FIXME: We could try harder here and handle a possible range
+      // or anti-range.  Hopefully the upcoming changes to range info
+      // will give us finer grained info, and we can avoid somersaults
+      // here.
+    }
+
+  return ALLOCA_UNBOUNDED;
+}
+
+// Return TRUE if SSA's definition is a cast from a signed type.
+// If so, set *INVALID_CASTED_TYPE to the signed type.
+
+static bool
+cast_from_signed_p (tree ssa, tree *invalid_casted_type)
+{
+  gimple *def = SSA_NAME_DEF_STMT (ssa);
+  if (def
+      && !gimple_nop_p (def)
+      && gimple_assign_cast_p (def)
+      && !TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (def))))
+    {
+      *invalid_casted_type = TREE_TYPE (gimple_assign_rhs1 (def));
+      return true;
+    }
+  return false;
+}
+
+// Return TURE if X has a maximum range of MAX, basically covering the
+// entire domain, in which case it's no range at all.
+
+static bool
+is_max (tree x, wide_int max)
+{
+  return wi::max_value (TREE_TYPE (x)) == max;
+}
+
+// Analyze the alloca call in STMT and return an `enum alloca_type'
+// explaining what type of alloca it is.  IS_VLA is set if the alloca
+// call is really a BUILT_IN_ALLOCA_WITH_ALIGN, signifying a VLA.
+//
+// If the alloca bound is determined to be too large, ASSUMED_LIMIT is
+// set to the bound used to determine this.  ASSUMED_LIMIT is only set
+// for ALLOCA_BOUND_MAYBE_LARGE and ALLOCA_BOUND_DEFINITELY_LARGE.
+//
+// If the alloca call may be too large because of a cast from a signed
+// type to an unsigned type, set *INVALID_CASTED_TYPE to the
+// problematic signed type.
+
+static enum alloca_type
+alloca_call_type (gimple *stmt, bool is_vla, wide_int *assumed_limit,
+		  tree *invalid_casted_type)
+{
+  gcc_assert (gimple_alloca_call_p (stmt));
+  tree len = gimple_call_arg (stmt, 0);
+  enum alloca_type w = ALLOCA_UNBOUNDED;
+  wide_int min, max;
+
+  gcc_assert (!is_vla || warn_vla_limit > 0);
+  gcc_assert (is_vla || warn_alloca_limit > 0);
+
+  // Adjust warn_alloca_max_size for VLAs, by taking the underlying
+  // type into account.
+  unsigned HOST_WIDE_INT max_size;
+  if (is_vla)
+    max_size = (unsigned HOST_WIDE_INT) warn_vla_limit;
+  else
+    max_size = (unsigned HOST_WIDE_INT) warn_alloca_limit;
+
+  // Check for the obviously bounded case.
+  if (TREE_CODE (len) == INTEGER_CST)
+    {
+      if (tree_to_uhwi (len) > max_size)
+	{
+	  *assumed_limit = len;
+	  return ALLOCA_BOUND_DEFINITELY_LARGE;
+	}
+      if (integer_zerop (len))
+	return ALLOCA_ARG_IS_ZERO;
+      w = ALLOCA_OK;
+    }
+  else if (TREE_CODE (len) != SSA_NAME)
+    return ALLOCA_UNBOUNDED;
+  // Check the range info if available.
+  else
+    {
+      if (value_range_type range_type = get_range_info (len, &min, &max))
+	{
+	  if (range_type == VR_RANGE)
+	    {
+	      if (wi::leu_p (max, max_size))
+		w = ALLOCA_OK;
+	      else if (is_max (len, max))
+		{
+		  // A cast may have created a range we don't care
+		  // about.  For instance, a cast from 16-bit to
+		  // 32-bit creates a range of 0..65535, even if there
+		  // is not really a determinable range in the
+		  // underlying code.  In this case, look through the
+		  // cast at the original argument, and fall through
+		  // to look at other alternatives.
+		  gimple *def = SSA_NAME_DEF_STMT (len);
+		  if (gimple_assign_cast_p (def))
+		    len = gimple_assign_rhs1 (def);
+		}
+	      else
+		{
+		  /* If `len' is merely a cast that is being
+		     calculated right before the call to alloca, look
+		     at the range for the original value.
+
+		     This avoids the cast creating a range where the
+		     original expression did not have a range:
+
+		     # RANGE [0, 18446744073709551615] NONZERO 4294967295
+		     _2 = (long unsigned int) n_7(D);
+		     p_9 = __builtin_alloca (_2);
+
+		     The correct thing would've been for the user to
+		     use size_t, which in the case above would've been
+		     'long unsigned int', and everything would've
+		     worked.  But we have to catch cases where the
+		     user is using some other compatible type for the
+		     call argument to alloca (say unsigned short).  */
+		  gimple *def = SSA_NAME_DEF_STMT (len);
+		  if (gimple_assign_cast_p (def))
+		    {
+		      len = gimple_assign_rhs1 (def);
+		      range_type = get_range_info (len, &min, &max);
+		    }
+
+		  if (range_type != VR_VARYING && is_max (len, max))
+		    {
+		      // Treat a max of the entire domain as if it had no
+		      // range info, and fall through the try other
+		      // alternatives.
+		    }
+		  else
+		    {
+		      *assumed_limit = max;
+		      return ALLOCA_BOUND_MAYBE_LARGE;
+		    }
+		}
+	    }
+	  else if (range_type == VR_ANTI_RANGE)
+	    {
+	      // There may be some wrapping around going on.  Catch it
+	      // with this heuristic.  Hopefully, this VR_ANTI_RANGE
+	      // nonsense will go away, and we won't have to catch the
+	      // sign conversion problems with this crap.
+	      if (cast_from_signed_p (len, invalid_casted_type))
+		return ALLOCA_CAST_FROM_SIGNED;
+
+	      // Fall thru and try other things.
+	    }
+	  else if (range_type == VR_VARYING)
+	    {
+	      // No easily determined range.  Try other things.
+	    }
+	}
+    }
+
+  // If we couldn't find anything, try a few heuristics for things we
+  // can easily determine.  Check these misc cases but only accept
+  // them if all predecessors have a known bound.
+  basic_block bb = gimple_bb (stmt);
+  if (w == ALLOCA_UNBOUNDED)
+    {
+      w = ALLOCA_OK;
+      for (unsigned ix = 0; ix < EDGE_COUNT (bb->preds); ix++)
+	{
+	  enum alloca_type w
+	    = alloca_call_type_by_arg (len, EDGE_PRED (bb, ix), max_size,
+				       assumed_limit);
+	  if (w != ALLOCA_OK)
+	    return w;
+	}
+    }
+
+  return w;
+}
+
+// Return TRUE if the alloca call in STMT is in a loop, otherwise
+// return FALSE. As an exception, ignore alloca calls for VLAs that
+// occur in a loop since those will be cleaned up when they go out of
+// scope.
+
+static bool
+in_loop_p (bool is_vla, gimple *stmt)
+{
+  basic_block bb = gimple_bb (stmt);
+  if (bb->loop_father
+      // ?? Functions with no loops get a loop_father?  I
+      // don't get it.  The following conditional seems to do
+      // the trick to exclude such nonsense.
+      && bb->loop_father->header != ENTRY_BLOCK_PTR_FOR_FN (cfun))
+    {
+      // Do not warn on VLAs occurring in a loop, since VLAs are
+      // guaranteed to be cleaned up when they go out of scope.
+      // That is, there is a corresponding __builtin_stack_restore
+      // at the end of the scope in which the VLA occurs.
+      tree fndecl = gimple_call_fn (stmt);
+      while (TREE_CODE (fndecl) == ADDR_EXPR)
+	fndecl = TREE_OPERAND (fndecl, 0);
+      if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+	  && is_vla
+	  && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA_WITH_ALIGN)
+	return false;
+
+      return true;
+    }
+  return false;
+}
+
+unsigned int
+pass_walloca::execute (function *fun)
+{
+  basic_block bb;
+  FOR_EACH_BB_FN (bb, fun)
+    {
+      for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);
+	   gsi_next (&si))
+	{
+	  gimple *stmt = gsi_stmt (si);
+	  location_t loc = gimple_location (stmt);
+
+	  if (!gimple_alloca_call_p (stmt))
+	    continue;
+	  gcc_assert (gimple_call_num_args (stmt) >= 1);
+
+	  bool is_vla = gimple_alloca_call_p (stmt)
+	    && gimple_call_alloca_for_var_p (as_a <gcall *> (stmt));
+
+	  // Strict mode whining for VLAs is handled by the front-end,
+	  // so we can safely ignore this case.  Also, ignore VLAs if
+	  // the user doesn't care about them.
+	  if (is_vla
+	      && (warn_vla > 0 || !warn_vla_limit))
+	    continue;
+
+	  if (!is_vla && (warn_alloca || !warn_alloca_limit))
+	    {
+	      if (warn_alloca)
+		warning_at (loc, OPT_Walloca, G_("use of %<alloca%>"));
+	      continue;
+	    }
+
+	  wide_int assumed_limit
+	    = wi::to_wide (integer_zero_node,
+			   TYPE_PRECISION (size_type_node));
+	  tree invalid_casted_type = NULL;
+	  enum alloca_type w = alloca_call_type (stmt, is_vla, &assumed_limit,
+						 &invalid_casted_type);
+
+	  // Even if we think the alloca call is OK, make sure it's
+	  // not in a loop.
+	  if (w == ALLOCA_OK && in_loop_p (is_vla, stmt))
+	    w = ALLOCA_IN_LOOP;
+
+	  enum opt_code wcode
+	    = is_vla ? OPT_Wvla_larger_than_ : OPT_Walloca_larger_than_;
+	  char buff[WIDE_INT_MAX_PRECISION / 4 + 4];
+	  switch (w)
+	    {
+	    case ALLOCA_OK:
+	      break;
+	    case ALLOCA_BOUND_MAYBE_LARGE:
+	      gcc_assert (assumed_limit != 0);
+	      if (warning_at (loc, wcode,
+			      is_vla ? G_("argument to variable-length array "
+					  "may be too large")
+			      : G_("argument to %<alloca%> may be too large")))
+		{
+		  print_decu (assumed_limit, buff);
+		  inform (loc, G_("limit is %u bytes, but argument "
+				  "may be as large as %s"),
+			  is_vla ? warn_vla_limit : warn_alloca_limit, buff);
+		}
+	      break;
+	    case ALLOCA_BOUND_DEFINITELY_LARGE:
+	      gcc_assert (assumed_limit != 0);
+	      if (warning_at (loc, wcode,
+			      is_vla ? G_("argument to variable-length array "
+					  "is too large")
+			      : G_("argument to %<alloca%> is too large")))
+		{
+		  print_decu (assumed_limit, buff);
+		  inform (loc, G_("limit is %u bytes, but argument is %s"),
+			  is_vla ? warn_vla_limit : warn_alloca_limit, buff);
+		}
+	      break;
+	    case ALLOCA_BOUND_UNKNOWN:
+	      warning_at (loc, wcode,
+			  is_vla ? G_("variable-length array bound is unknown")
+			  : G_("%<alloca%> bound is unknown"));
+	      break;
+	    case ALLOCA_UNBOUNDED:
+	      warning_at (loc, wcode,
+			  is_vla ? G_("unbounded use of variable-length array")
+			  : G_("unbounded use of %<alloca%>"));
+	      break;
+	    case ALLOCA_IN_LOOP:
+	      gcc_assert (!is_vla);
+	      warning_at (loc, wcode, G_("use of %<alloca%> within a loop"));
+	      break;
+	    case ALLOCA_CAST_FROM_SIGNED:
+	      gcc_assert (invalid_casted_type != NULL_TREE);
+	      warning_at (loc, wcode,
+			  is_vla ? G_("argument to variable-length array "
+				      "may be too large due to "
+				      "conversion from %qT to %qT")
+			  : G_("argument to %<alloca%> may be too large "
+			       "due to conversion from %qT to %qT"),
+			  invalid_casted_type, size_type_node);
+	      break;
+	    case ALLOCA_ARG_IS_ZERO:
+	      warning_at (loc, wcode,
+			  is_vla ? G_("argument to variable-length array "
+				      "is zero")
+			  : G_("argument to %<alloca%> is zero"));
+	      break;
+	    default:
+	      gcc_unreachable ();
+	    }
+	}
+    }
+  return 0;
+}
+
+gimple_opt_pass *
+make_pass_walloca (gcc::context *ctxt)
+{
+  return new pass_walloca (ctxt);
+}
diff --git a/gcc/passes.def b/gcc/passes.def
index 3647e90..298b455 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3.  If not see
   NEXT_PASS (pass_warn_function_return);
   NEXT_PASS (pass_expand_omp);
   NEXT_PASS (pass_build_cgraph_edges);
+  NEXT_PASS (pass_walloca, /*strict_mode_p=*/true);
   TERMINATE_PASS_LIST (all_lowering_passes)
 
   /* Interprocedural optimization passes.  */
@@ -247,6 +248,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_laddress);
       NEXT_PASS (pass_lim);
       NEXT_PASS (pass_split_crit_edges);
+      NEXT_PASS (pass_walloca, /*strict_mode_p=*/false);
       NEXT_PASS (pass_pre);
       NEXT_PASS (pass_sink_code);
       NEXT_PASS (pass_sancov);
diff --git a/gcc/testsuite/gcc.dg/Walloca-1.c b/gcc/testsuite/gcc.dg/Walloca-1.c
new file mode 100644
index 0000000..34a20c3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-1.c
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=2000 -O2" } */
+
+#define alloca __builtin_alloca
+
+typedef __SIZE_TYPE__ size_t;
+extern size_t strlen(const char *);
+
+extern void useit (char *);
+
+int num;
+
+void foo1 (size_t len, size_t len2, size_t len3)
+{
+  int i;
+
+  for (i=0; i < 123; ++i)
+    {
+      char *s = alloca (566);	/* { dg-warning "'alloca' within a loop" } */
+      useit (s);
+    }
+
+  char *s = alloca (123);
+  useit (s);			// OK, constant argument to alloca
+
+  s = alloca (num);		// { dg-warning "large due to conversion" }
+  useit (s);
+
+  s = alloca(90000);		/* { dg-warning "is too large" } */
+  useit (s);
+
+  if (len < 2000)
+    {
+      s = alloca(len);		// OK, bounded
+      useit (s);
+    }
+
+  if (len + len2 < 2000)	// OK, bounded
+    {
+      s = alloca(len + len2);
+      useit (s);
+    }
+
+  if (len3 <= 2001)
+    {
+      s = alloca(len3);		/* { dg-warning "may be too large" } */
+      useit(s);
+    }
+}
+
+void foo2 (__SIZE_TYPE__ len)
+{
+  // Test that a direct call to __builtin_alloca_with_align is not confused
+  // with a VLA.
+  void *p = __builtin_alloca_with_align (len, 8); // { dg-warning "unbounded use of 'alloca'" }
+  useit (p);
+}
+
+void foo3 (unsigned char a)
+{
+  if (a == 0)
+    useit (__builtin_alloca (a)); // { dg-warning "argument to 'alloca' is zero" }
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-2.c b/gcc/testsuite/gcc.dg/Walloca-2.c
new file mode 100644
index 0000000..284b34e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-2.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=2000 -O2" } */
+
+void f (void *);
+
+void
+g1 (int n)
+{
+  void *p;
+  if (n > 0 && n < 2000)
+    p = __builtin_alloca (n);
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
+
+void
+g2 (int n)
+{
+  void *p;
+  if (n < 2000)
+    p = __builtin_alloca (n); // { dg-warning "large due to conversion" }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
+
+void
+g3 (int n)
+{
+  void *p;
+  if (n > 0 && n < 3000)
+    {
+      p = __builtin_alloca (n); // { dg-warning "'alloca' may be too large" }
+      // { dg-message "note:.*argument may be as large as 2999" "note" { target *-*-* } 34 }
+    }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-3.c b/gcc/testsuite/gcc.dg/Walloca-3.c
new file mode 100644
index 0000000..5345197
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-3.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=2000 -O2" } */
+
+void f (void *);
+
+__SIZE_TYPE__ LIMIT;
+
+// Warn when there is an alloca bound, but it is an unknown bound.
+
+void
+g1 (__SIZE_TYPE__ n)
+{
+  void *p;
+  if (n < LIMIT)
+    p = __builtin_alloca (n); // { dg-warning "'alloca' bound is unknown" }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
+
+// Similar to the above, but do not get confused by the upcast.
+
+unsigned short SHORT_LIMIT;
+void
+g2 (unsigned short n)
+{
+  void *p;
+  if (n < SHORT_LIMIT)
+    p = __builtin_alloca (n); // { dg-warning "'alloca' bound is unknown" }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-4.c b/gcc/testsuite/gcc.dg/Walloca-4.c
new file mode 100644
index 0000000..d96cc4e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-4.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=5000 -O2" } */
+/* { dg-xfail-if "Currently broken but Andrew's work should fix this" { *-*-* } } */
+
+// Should be another variant of Walloca-7.c.
+// This should not warn, as we have a known bound within limits.
+
+ char *
+ _i18n_number_rewrite (char *w, char *rear_ptr)
+{
+
+  char *src;
+ _Bool 
+      use_alloca = (((rear_ptr - w) * sizeof (char)) < 4096U);
+ if (use_alloca)
+    src = (char *) __builtin_alloca ((rear_ptr - w) * sizeof (char));
+  else
+    src = (char *) __builtin_malloc ((rear_ptr - w) * sizeof (char));
+  return src;
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-5.c b/gcc/testsuite/gcc.dg/Walloca-5.c
new file mode 100644
index 0000000..5ed1171
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-5.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=123 -O2" } */
+/* { dg-xfail-if "Currently broken but Andrew's work should fix this" { *-*-* } } */
+
+/* The argument to alloca ends up having a range of 0..MAXINT(32bits),
+   so we think we have a range because of the upcast.  Consequently,
+   we warn with "alloca may be too large", but we should technically
+   warn with "unbounded use of alloca".
+
+   We currently drill through casts to figure this stuff out, but we
+   get confused because it's not just a cast.  It's a cast, plus a
+   multiply.
+
+   <bb 2>:
+  # RANGE [0, 4294967295] NONZERO 4294967295
+  _1 = (long unsigned int) something_4(D);
+  # RANGE [0, 34359738360] NONZERO 34359738360
+  _2 = _1 * 8;
+  _3 = __builtin_alloca (_2);
+
+  I don't know whether it's even worth such fine-grained warnings.
+  Perhaps we should generically warn everywhere with "alloca may be
+  too large".
+
+  I'm hoping that this particular case will be easier to diagnose with
+  Andrew's work.  */
+
+void useit(void *);
+void foobar(unsigned int something)
+{
+  useit(__builtin_alloca (something * sizeof (const char *))); // { dg-warning "unbounded use of alloca" "" { xfail *-*-* } }
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-6.c b/gcc/testsuite/gcc.dg/Walloca-6.c
new file mode 100644
index 0000000..b4d8d41
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-6.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=256 -O2" } */
+/* { dg-xfail-if "Currently broken but Andrew's work should fix this" { *-*-* } } */
+
+void f (void*);
+void g (__SIZE_TYPE__ n)
+{
+  // No warning on this case.  Range is easily determinable.
+  if (n > 0 && n < 256)
+    f (__builtin_alloca (n));
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-7.c b/gcc/testsuite/gcc.dg/Walloca-7.c
new file mode 100644
index 0000000..d6581a5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-7.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca -O0" } */
+
+extern void f(void *);
+
+void foo(void)
+{
+  // Test that strict -Walloca works even without optimization.
+  f (__builtin_alloca(500)); // { dg-warning "use of 'alloca'" }
+}
+
+void bar(void)
+{
+  // Test that we warn on alloca() calls, not just __builtin_alloca calls.
+  extern void *alloca(__SIZE_TYPE__);
+  f (alloca (123)); // { dg-warning "use of 'alloca'" }
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-8.c b/gcc/testsuite/gcc.dg/Walloca-8.c
new file mode 100644
index 0000000..a4a1204
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-8.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=2000 -O2" } */
+
+void *p;
+void
+foo (__SIZE_TYPE__ len)
+{
+  if (len < 2000 / sizeof (void *))
+    p = __builtin_alloca (len * sizeof (void *));
+  else
+    p = __builtin_malloc (len * sizeof (void *));
+}
diff --git a/gcc/testsuite/gcc.dg/Wvla-1.c b/gcc/testsuite/gcc.dg/Wvla-1.c
new file mode 100644
index 0000000..384c930
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wvla-1.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-Wvla-larger-than=100 -O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern void useit (char *);
+
+int num;
+
+void test_vlas (size_t num)
+{
+  char str2[num];		/* { dg-warning "unbounded use" } */
+  useit(str2);
+
+  num = 98;
+  for (int i=0; i < 1234; ++i) {
+    char str[num];	        // OK, VLA in a loop, but it is a
+				// known size *AND* the compiler takes
+				// care of cleaning up between
+				// iterations with
+				// __builtin_stack_restore.
+    useit(str);
+  }
+}
diff --git a/gcc/testsuite/gcc.dg/Wvla-2.c b/gcc/testsuite/gcc.dg/Wvla-2.c
new file mode 100644
index 0000000..96814dc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wvla-2.c
@@ -0,0 +1,70 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target stdint_types } */
+/* { dg-options "-O2 -Wvla-larger-than=40" } */
+
+#include <stdint.h>
+
+void f0 (void *);
+void
+f1 (__SIZE_TYPE__ a)
+{
+  if (a <= 10)
+    {
+      // 10 * 4 bytes = 40: OK!
+      uint32_t x[a];
+      f0 (x);
+    }
+}
+
+void
+f2 (__SIZE_TYPE__ a)
+{
+  if (a <= 11)
+    {
+      // 11 * 4 bytes = 44: Not OK.
+      uint32_t x[a]; // { dg-warning "array may be too large" }
+      // { dg-message "note:.*argument may be as large as 44" "note" { target *-*-* } 25 }
+      f0 (x);
+    }
+}
+
+void
+f3 (__SIZE_TYPE__ a, __SIZE_TYPE__ b)
+{
+  if (a <= 5 && b <= 3)
+    {
+      // 5 * 3 * 4 bytes = 60: Not OK.
+      uint32_t x[a][b]; // { dg-warning "array may be too large" }
+      f0 (x);
+    }
+}
+
+void
+f4 (__SIZE_TYPE__ a, __SIZE_TYPE__ b)
+{
+  if (a <= 5 && b <= 2)
+    {
+      // 5 * 2 * 4 bytes = 40 bytes: OK!
+      uint32_t x[a][b];
+      f0 (x);
+    }
+}
+
+void
+f5 (__SIZE_TYPE__ len)
+{
+  // Test that a direct call to __builtin_alloca_with_align is not
+  // confused with a VLA.
+  void *p = __builtin_alloca_with_align (len, 8);
+  f0 (p);
+}
+
+void
+f6 (unsigned stuff)
+{
+  int n = 7000;
+  do {
+    char a[n]; // { dg-warning "variable-length array is too large" }
+    f0 (a);
+  } while (stuff--);
+}
diff --git a/gcc/testsuite/gcc.dg/Wvla-3.c b/gcc/testsuite/gcc.dg/Wvla-3.c
new file mode 100644
index 0000000..5124476
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wvla-3.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca -O2" } */
+
+// Make sure we don't warn on VLA with -Walloca.
+
+void f (void*);
+
+void h1 (unsigned n)
+{
+  int a [n];
+  f (a);
+}
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 36299a6..57b61f4 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -469,6 +469,7 @@ extern simple_ipa_opt_pass *make_pass_ipa_oacc (gcc::context *ctxt);
 extern simple_ipa_opt_pass *make_pass_ipa_oacc_kernels (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_gen_hsail (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_warn_nonnull_compare (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_walloca (gcc::context *ctxt);
 
 /* IPA Passes */
 extern simple_ipa_opt_pass *make_pass_ipa_lower_emutls (gcc::context *ctxt);

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

end of thread, other threads:[~2016-08-02 12:55 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-08 11:48 RFA: new pass to warn on questionable uses of alloca() and VLAs Aldy Hernandez
2016-07-10 22:09 ` Martin Sebor
2016-07-11 14:32   ` Jeff Law
2016-07-15 17:05   ` Aldy Hernandez
2016-07-16 21:08     ` Martin Sebor
2016-07-16 23:59       ` Martin Sebor
2016-07-18 10:45       ` Aldy Hernandez
2016-07-19  3:14         ` Martin Sebor
2016-07-19 11:03           ` Aldy Hernandez
2016-07-19 17:54             ` Jeff Law
2016-07-19 19:06               ` Aldy Hernandez
2016-08-01 20:35             ` Joseph Myers
2016-08-02 12:55               ` Aldy Hernandez
2016-07-17 15:53     ` Manuel López-Ibáñez
2016-07-18 10:10       ` Aldy Hernandez
2016-07-19 17:47       ` Jeff Law
2016-07-19 18:07         ` Manuel López-Ibáñez
2016-07-19 19:05         ` Aldy Hernandez
2016-07-10 23:41 ` Manuel López-Ibáñez
2016-07-11 10:10   ` Aldy Hernandez
2016-07-11 14:22     ` Manuel López-Ibáñez
2016-07-11 15:08     ` Martin Sebor
2016-07-11 15:40       ` Aldy Hernandez
2016-07-11 17:56         ` Martin Sebor
2016-07-15 17:05           ` Aldy Hernandez
2016-07-11 14:25 ` Jeff Law

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).