Commit adc577c5 by Aldy Hernandez Committed by Aldy Hernandez

Makefile.in (OBJS): Add gimple-ssa-warn-alloca.o.

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

From-SVN: r241318
parent c354ab1f
2016-10-18 Aldy Hernandez <aldyh@redhat.com>
* 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-alloca.c: New file.
* doc/invoke.texi: Document -Walloca, -Walloca-larger-than=, and
-Wvla-larger-than= options.
2016-10-18 Thomas Schwinge <thomas@codesourcery.com>
* cfg.c (clear_bb_flags): Use FOR_ALL_BB_FN.
......
......@@ -1298,6 +1298,7 @@ OBJS = \
gimple-ssa-split-paths.o \
gimple-ssa-strength-reduction.o \
gimple-ssa-sprintf.o \
gimple-ssa-warn-alloca.o \
gimple-streamer-in.o \
gimple-streamer-out.o \
gimple-walk.o \
......
2016-06-16 Aldy Hernandez <aldyh@redhat.com>
* c.opt (Walloca): New.
(Walloca-larger-than=): New.
(Wvla-larger-than=): New.
2016-10-17 Marek Polacek <polacek@redhat.com>
* c-warn.c (find_array_ref_with_const_idx_r): Remove parameter names.
......
......@@ -380,6 +380,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. */
......
......@@ -295,6 +295,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
......@@ -1030,6 +1040,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.
......
......@@ -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 -Wbool-operation @gol
-Wno-builtin-macro-redefined -Wc90-c99-compat -Wc99-c11-compat @gol
......@@ -313,7 +314,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
......@@ -4976,6 +4977,73 @@ 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
void func (size_t n)
@{
void *p;
if (n <= 1000)
p = alloca (n);
else
p = malloc (n);
f (p);
@}
@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
void func ()
@{
void *p = alloca (n);
f (p);
@}
@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
void func (signed int n)
@{
if (n < 500)
@{
p = alloca (n);
f (p);
@}
@}
@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
......@@ -6172,9 +6240,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
......
......@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_expand_omp);
NEXT_PASS (pass_build_cgraph_edges);
NEXT_PASS (pass_sprintf_length, false);
NEXT_PASS (pass_walloca, /*strict_mode_p=*/true);
TERMINATE_PASS_LIST (all_lowering_passes)
/* Interprocedural optimization passes. */
......@@ -251,6 +252,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, false);
NEXT_PASS (pass_pre);
NEXT_PASS (pass_sink_code);
NEXT_PASS (pass_sancov);
......
/* { 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" }
}
/* { dg-do compile } */
/* { dg-options "-Walloca-larger-than=2000 -O2" } */
// Test when the conditionals are incorrectly reversed.
void f (void *);
void foo (__SIZE_TYPE__ len)
{
void *p;
if (len < 500)
p = __builtin_malloc (len);
else
p = __builtin_alloca (len); // { dg-warning "argument to .alloca. may be too large" }
f (p);
}
void bar (__SIZE_TYPE__ len)
{
void *p;
if (len > 500)
p = __builtin_alloca (len); // { dg-warning "argument to .alloca. may be too large" }
else
p = __builtin_malloc (len);
f (p);
}
/* { 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);
}
/* { 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);
}
/* { dg-do compile } */
/* { dg-options "-Walloca-larger-than=5000 -O2" } */
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;
}
/* { 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 *-*-* } }
}
/* { 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));
}
/* { 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'" }
}
/* { 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 *));
}
/* { dg-do compile } */
/* { dg-options "-Walloca-larger-than=5000 -O2" } */
extern void useit(char *);
int
foobar (unsigned short length)
{
char *pbuf;
__SIZE_TYPE__ size = (__SIZE_TYPE__) length;
if (size < 4032)
pbuf = (char *) __builtin_alloca(size);
else
pbuf = (char *) __builtin_malloc (size);
useit(pbuf);
return 0;
}
/* { 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);
}
}
/* { 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--);
}
/* { 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);
}
......@@ -472,6 +472,7 @@ 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_sprintf_length (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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment