diff options
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/c-family/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/c-family/c-common.c | 27 | ||||
-rw-r--r-- | gcc/doc/extend.texi | 88 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/builtin_alloca.C | 191 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/builtins-68.c | 110 |
7 files changed, 434 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8db1f39..3c629ef 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2016-02-23 Martin Sebor <msebor@redhat.com> + + PR c/69759 + * doc/extend.texi (Other Builtins): Document __builtin_alloca and + __builtin_alloca_with_align. + 2016-02-23 Richard Henderson <rth@redhat.com> * config/i386/i386-c.c (ix86_target_macros): Remove __SEG_TLS. diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index f11503e..66d74f4 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2016-02-22 Martin Sebor <msebor@redhat.com> + + PR middle-end/69780 + * c-common.c (check_builtin_function_arguments): Validate and + reject invalid arguments to __builtin_alloca_with_align. + 2016-02-20 Mark Wielaard <mjw@redhat.com> PR c/28901 diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 8b29d82..71da6e9 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -9818,6 +9818,33 @@ check_builtin_function_arguments (tree fndecl, int nargs, tree *args) switch (DECL_FUNCTION_CODE (fndecl)) { + case BUILT_IN_ALLOCA_WITH_ALIGN: + { + /* Get the requested alignment (in bits) if it's a constant + integer expression. */ + unsigned HOST_WIDE_INT align + = tree_fits_uhwi_p (args[1]) ? tree_to_uhwi (args[1]) : 0; + + /* Determine if the requested alignment is a power of 2. */ + if ((align & (align - 1))) + align = 0; + + /* The maximum alignment in bits corresponding to the same + maximum in bytes enforced in check_user_alignment(). */ + unsigned maxalign = (UINT_MAX >> 1) + 1; + + /* Reject invalid alignments. */ + if (align < BITS_PER_UNIT || maxalign < align) + { + error_at (EXPR_LOC_OR_LOC (args[1], input_location), + "second argument to function %qE must be a constant " + "integer power of 2 between %qi and %qu bits", + fndecl, BITS_PER_UNIT, maxalign); + return false; + } + return true; + } + case BUILT_IN_CONSTANT_P: return builtin_function_validate_nargs (fndecl, nargs, 1); diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 4abb0df..10a42b6 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -10127,6 +10127,8 @@ in the Cilk Plus language manual which can be found at @node Other Builtins @section Other Built-in Functions Provided by GCC @cindex built-in functions +@findex __builtin_alloca +@findex __builtin_alloca_with_align @findex __builtin_call_with_static_chain @findex __builtin_fpclassify @findex __builtin_isfinite @@ -10673,6 +10675,92 @@ In the same fashion, GCC provides @code{fpclassify}, @code{isfinite}, @code{__builtin_} prefixed. The @code{isinf} and @code{isnan} built-in functions appear both with and without the @code{__builtin_} prefix. +@deftypefn {Built-in Function} void *__builtin_alloca (size_t size) +The @code{__builtin_alloca} function must be called at block scope. +The function allocates an object @var{size} bytes large on the stack +of the calling function. The object is aligned on the default stack +alignment boundary for the target determined by the +@code{__BIGGEST_ALIGNMENT__} macro. The @code{__builtin_alloca} +function returns a pointer to the first byte of the allocated object. +The lifetime of the allocated object ends just before the calling +function returns to its caller. This is so even when +@code{__builtin_alloca} is called within a nested block. + +For example, the following function allocates eight objects of @code{n} +bytes each on the stack, storing a pointer to each in consecutive elements +of the array @code{a}. It then passes the array to function @code{g} +which can safely use the storage pointed to by each of the array elements. + +@smallexample +void f (unsigned n) +@{ + void *a [8]; + for (int i = 0; i != 8; ++i) + a [i] = __builtin_alloca (n); + + g (a, n); // @r{safe} +@} +@end smallexample + +Since the @code{__builtin_alloca} function doesn't validate its argument +it is the responsibility of its caller to make sure the argument doesn't +cause it to exceed the stack size limit. +The @code{__builtin_alloca} function is provided to make it possible to +allocate on the stack arrays of bytes with an upper bound that may be +computed at run time. Since C99 @xref{Variable Length} Arrays offer +similar functionality under a portable, more convenient, and safer +interface they are recommended instead, in both C99 and C++ programs +where GCC provides them as an extension. + +@end deftypefn + +@deftypefn {Built-in Function} void *__builtin_alloca_with_align (size_t size, size_t alignment) +The @code{__builtin_alloca_with_align} function must be called at block +scope. The function allocates an object @var{size} bytes large on +the stack of the calling function. The allocated object is aligned on +the boundary specified by the argument @var{alignment} whose unit is given +in bits (not bytes). The @var{size} argument must be positive and not +exceed the stack size limit. The @var{alignment} argument must be a constant +integer expression that evaluates to a power of 2 greater than or equal to +@code{CHAR_BIT} and less than some unspecified maximum. Invocations +with other values are rejected with an error indicating the valid bounds. +The function returns a pointer to the first byte of the allocated object. +The lifetime of the allocated object ends at the end of the block in which +the function was called. The allocated storage is released no later than +just before the calling function returns to its caller, but may be released +at the end of the block in which the function was called. + +For example, in the following function the call to @code{g} is unsafe +because when @code{overalign} is non-zero, the space allocated by +@code{__builtin_alloca_with_align} may have been released at the end +of the @code{if} statement in which it was called. + +@smallexample +void f (unsigned n, bool overalign) +@{ + void *p; + if (overalign) + p = __builtin_alloca_with_align (n, 64 /* bits */); + else + p = __builtin_alloc (n); + + g (p, n); // @r{unsafe} +@} +@end smallexample + +Since the @code{__builtin_alloca_with_align} function doesn't validate its +@var{size} argument it is the responsibility of its caller to make sure +the argument doesn't cause it to exceed the stack size limit. +The @code{__builtin_alloca_with_align} function is provided to make +it possible to allocate on the stack overaligned arrays of bytes with +an upper bound that may be computed at run time. Since C99 +@xref{Variable Length} Arrays offer the same functionality under +a portable, more convenient, and safer interface they are recommended +instead, in both C99 and C++ programs where GCC provides them as +an extension. + +@end deftypefn + @deftypefn {Built-in Function} int __builtin_types_compatible_p (@var{type1}, @var{type2}) You can use the built-in function @code{__builtin_types_compatible_p} to diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b824dfb..9fa77b1 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2016-02-23 Martin Sebor <msebor@redhat.com> + + PR middle-end/69780 + * g++.dg/ext/builtin_alloca.C: New test. + * gcc.dg/builtins-68.c: New test. + 2016-02-23 Richard Henderson <rth@redhat.com> * gcc.target/i386/addr-space-3.c: Remove test. diff --git a/gcc/testsuite/g++.dg/ext/builtin_alloca.C b/gcc/testsuite/g++.dg/ext/builtin_alloca.C new file mode 100644 index 0000000..10a9bdc --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/builtin_alloca.C @@ -0,0 +1,191 @@ +// PR middle-end/69780 - [4.9/5/6 Regression] ICE on +// __builtin_alloca_with_align with small alignment +// { dg-require-effective-target alloca } +// { dg-do compile } + +#define CHAR_BIT __CHAR_BIT__ +#define INT_MAX __INT_MAX__ +#define INT_MIN (-INT_MAX - 1) +#define LONG_MAX __LONG_MAX__ +#define LLONG_MAX __LONG_LONG_MAX__ + +static void* p; + +// Verify that valid __builtin_alloca_with_align expressions are accepted. +void test_valid (int n) +{ + enum { + A1 = CHAR_BIT * 1, + A2 = CHAR_BIT * 2, + A4 = CHAR_BIT * 4, + A8 = CHAR_BIT * 8, + A16 = CHAR_BIT * 16, + A32 = CHAR_BIT * 32 + }; + + const int a1 = A1; + const int a2 = A2; + const int a4 = A4; + const int a8 = A8; + const int a16 = A16; + const int a32 = A32; + + // Valid alignments are power of 2 positive multiples of CHAR_BIT. + p = __builtin_alloca_with_align (n, CHAR_BIT * 1); + p = __builtin_alloca_with_align (n, CHAR_BIT * 2); + p = __builtin_alloca_with_align (n, CHAR_BIT * 4); + p = __builtin_alloca_with_align (n, CHAR_BIT * 8); + p = __builtin_alloca_with_align (n, CHAR_BIT * 16); + p = __builtin_alloca_with_align (n, CHAR_BIT * 32); + + p = __builtin_alloca_with_align (n, A1); + p = __builtin_alloca_with_align (n, A2); + p = __builtin_alloca_with_align (n, A4); + p = __builtin_alloca_with_align (n, A8); + p = __builtin_alloca_with_align (n, A16); + p = __builtin_alloca_with_align (n, A32); + + p = __builtin_alloca_with_align (n, a1); + p = __builtin_alloca_with_align (n, a2); + p = __builtin_alloca_with_align (n, a4); + p = __builtin_alloca_with_align (n, a8); + p = __builtin_alloca_with_align (n, a16); + p = __builtin_alloca_with_align (n, a32); +} + +template <int A> struct X { enum { Align = A }; }; + +template <int A> +void test_valid_template (int n) +{ + // Valid alignments are power of 2 positive multiples of CHAR_BIT. + p = __builtin_alloca_with_align (n, A); +} + +template void test_valid_template<CHAR_BIT>(int); +template void test_valid_template<CHAR_BIT * 2>(int); +template void test_valid_template<CHAR_BIT * 4>(int); +template void test_valid_template<CHAR_BIT * 8>(int); +template void test_valid_template<CHAR_BIT * 16>(int); +template void test_valid_template<CHAR_BIT * 32>(int); + +// Exercise the alignment in a dependent context. +template <int A> +void test_valid_template_dep (int n) +{ + // Valid alignments are power of 2 positive multiples of CHAR_BIT. + p = __builtin_alloca_with_align (n, X<A>::Align); +} + +template void test_valid_template_dep<CHAR_BIT>(int); +template void test_valid_template_dep<CHAR_BIT * 2>(int); +template void test_valid_template_dep<CHAR_BIT * 4>(int); +template void test_valid_template_dep<CHAR_BIT * 8>(int); +template void test_valid_template_dep<CHAR_BIT * 16>(int); +template void test_valid_template_dep<CHAR_BIT * 32>(int); + +// Invalid size must be rejected (and not cause an ICE). +void test_arg1_non_int (int n) +{ + extern void f (); + + p = __builtin_alloca_with_align ((void*)0, 32); // { dg-error "invalid conversion" } + + p = __builtin_alloca_with_align ("", 32); // { dg-error "invalid conversion" } + p = __builtin_alloca_with_align (L"", 32); // { dg-error "invalid conversion" } + p = __builtin_alloca_with_align (f, 32); // { dg-error "invalid conversion" } +} + +// Non-integer alignment must be rejected. +void test_arg2_non_int (int n) +{ + // Verify the full text of the diagnostic just once. + p = __builtin_alloca_with_align (n, 0.0); // { dg-error "second argument to function .__builtin_alloca_with_align. must be a constant integer power of 2 between .8. and " } + + p = __builtin_alloca_with_align (n, (void*)0); // { dg-error "invalid conversion|must be a constant integer" } + p = __builtin_alloca_with_align (n, ""); // { dg-error "invalid conversion|must be a constant integer" } + p = __builtin_alloca_with_align (n, L""); // { dg-error "invalid conversion|must be a constant integer" } +} + +// Integer alignment that's not a constant expression must be rejected. +void test_arg2_non_const (int n, int a1) +{ + extern const int a2; + static volatile const int a3 = CHAR_BIT; + + p = __builtin_alloca_with_align (n, a1); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, a2); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, a3); // { dg-error "must be a constant integer" } +} + +// Constant integer alignment that's not a power of 2 positive multiple +// of CHAR_BIT must be rejected. +void test_arg2_non_pow2 (int n) +{ + p = __builtin_alloca_with_align (n, INT_MIN); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, -1); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, !1); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, !0); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 0); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 1); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 2); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 3); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 4); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 5); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 6); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 7); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 9); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 10); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 11); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 12); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 13); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 14); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 15); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 17); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 31); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 33); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 63); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 65); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, INT_MAX); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, ~0U); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, LONG_MAX); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, ~0LU); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, 1LLU << 34); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, LLONG_MAX); // { dg-error "must be a constant integer" } + p = __builtin_alloca_with_align (n, ~0LLU); // { dg-error "must be a constant integer" } +} + +// Exercise invalid alignment specified by a template argument. +template <int A> +void test_invalid_template_1 (int n) +{ + // Valid alignments are power of 2 positive multiples of CHAR_BIT. + p = __builtin_alloca_with_align (n, A); // { dg-error "must be a constant integer" } +} + +template void test_invalid_template_1<1>(int); + +template <int A> +void test_invalid_template_7 (int n) +{ + p = __builtin_alloca_with_align (n, A); // { dg-error "must be a constant integer" } +} + +template void test_invalid_template_7<7>(int); + +template <int A> +void test_invalid_template_9 (int n) +{ + p = __builtin_alloca_with_align (n, A); // { dg-error "must be a constant integer" } +} + +template void test_invalid_template_9<9>(int); + +// Exercise invalid alignment specified by a template dependent argument. +template <int A> +void test_invalid_template_dep_1 (int n) +{ + p = __builtin_alloca_with_align (n, X<A>::Align); // { dg-error "must be a constant integer" } +} + +template void test_invalid_template_dep_1<1>(int); diff --git a/gcc/testsuite/gcc.dg/builtins-68.c b/gcc/testsuite/gcc.dg/builtins-68.c new file mode 100644 index 0000000..d2e65d0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtins-68.c @@ -0,0 +1,110 @@ +/* PR middle-end/69780 - [4.9/5/6 Regression] ICE on + __builtin_alloca_with_align with small alignment */ +/* { dg-require-effective-target alloca } */ +/* { dg-do compile } */ +/* { dg-options "-Wno-long-long" } */ + +#define CHAR_BIT __CHAR_BIT__ +#define INT_MAX __INT_MAX__ +#define INT_MIN (-INT_MAX - 1) +#define LONG_MAX __LONG_MAX__ +#define LLONG_MAX __LONG_LONG_MAX__ + +static void* p; + +/* Verify that valid __builtin_alloca_with_align expressions are accepted. */ +void test_valid (int n) +{ + enum { + A1 = CHAR_BIT * 1, + A2 = CHAR_BIT * 2, + A4 = CHAR_BIT * 4, + A8 = CHAR_BIT * 8, + A16 = CHAR_BIT * 16, + A32 = CHAR_BIT * 32 + }; + + /* Valid alignments are power of 2 positive multiples of CHAR_BIT. */ + p = __builtin_alloca_with_align (n, CHAR_BIT * 1); + p = __builtin_alloca_with_align (n, CHAR_BIT * 2); + p = __builtin_alloca_with_align (n, CHAR_BIT * 4); + p = __builtin_alloca_with_align (n, CHAR_BIT * 8); + p = __builtin_alloca_with_align (n, CHAR_BIT * 16); + p = __builtin_alloca_with_align (n, CHAR_BIT * 32); + + p = __builtin_alloca_with_align (n, A1); + p = __builtin_alloca_with_align (n, A2); + p = __builtin_alloca_with_align (n, A4); + p = __builtin_alloca_with_align (n, A8); + p = __builtin_alloca_with_align (n, A16); + p = __builtin_alloca_with_align (n, A32); +} + +/* Non-integer alignments must be rejected. */ +void test_arg2_non_int (int n) +{ + /* Verify the full text of the diagnostic just once. */ + p = __builtin_alloca_with_align (n, 0.0); /* { dg-error "second argument to function .__builtin_alloca_with_align. must be a constant integer power of 2 between .8. and " } */ + + /* Disable diagnostic complaining about converting void* to int that + preempts the "constant integer expression" error. */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wint-conversion" + + p = __builtin_alloca_with_align (n, (void*)0); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, ""); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, L""); /* { dg-error "must be a constant integer" } */ + +#pragma GCC diagnostic pop + +} + +/* Integer alignment that's not a constant expression must be rejected. */ +void test_arg2_non_const (int n, int a1) +{ + extern const int a2; + static const int a3 = CHAR_BIT; + static volatile const int a4 = CHAR_BIT; + + p = __builtin_alloca_with_align (n, a1); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, a2); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, a3); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, a4); /* { dg-error "must be a constant integer" } */ +} + +/* Constant integer alignment that's not a power of 2 positive multiple + of CHAR_BIT less than (1LLU << 32) must be rejected. */ +void test_arg2_non_pow2 (int n) +{ + p = __builtin_alloca_with_align (n, INT_MIN); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, -1); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, !1); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, !0); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 0); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 1); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 2); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 3); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 4); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 5); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 6); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 7); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 9); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 10); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 11); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 12); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 13); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 14); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 15); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 17); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 31); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 33); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 63); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 65); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, INT_MAX); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, ~0U); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, LONG_MAX); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, ~0LU); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, 1LLU << 34); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, LLONG_MAX); /* { dg-error "must be a constant integer" } */ + p = __builtin_alloca_with_align (n, ~0LLU); /* { dg-error "must be a constant integer" } */ +} |