PR middle-end/69780 - [4.9/5/6 Regression] ICE on __builtin_alloca_with_align

PR middle-end/69780 - [4.9/5/6 Regression] ICE on __builtin_alloca_with_align
	with small alignment
PR c/69759 - __builtin_alloca and __builtin_alloca_with_align undocumented

gcc/c-family/ChangeLog:
	* c-common.c (check_builtin_function_arguments): Validate and reject
	invalid arguments to __builtin_alloca_with_align.

gcc/ChangeLog:
	* doc/extend.texi (Other Builtins): Document __builtin_alloca and
	__builtin_alloca_with_align.

gcc/testsuite/ChangeLog:
	* g++.dg/ext/builtin_alloca.C: New test.
	* gcc.dg/builtins-68.c: New test.

From-SVN: r233640
This commit is contained in:
Martin Sebor 2016-02-23 18:09:37 +00:00 committed by Martin Sebor
parent 162cc7e383
commit 35886f0bd4
7 changed files with 434 additions and 0 deletions

View file

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

View file

@ -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

View file

@ -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);

View file

@ -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

View file

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

View file

@ -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);

View file

@ -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" } */
}