re PR middle-end/65958 (-fstack-check breaks alloca on architectures using generic stack checking)

PR middle-end/65958
	* gimplify.c (struct gimplify_ctx): Turn boolean fields into 1-bit
	fields, add keep_stack and reorder them.
	(gimplify_bind_expr): Save gimplify_ctxp->keep_stack on entry then
	set it to false.  Do not insert a stack save/restore pair if it has
	been set to true by the gimplification of the statements.
	Restore it to the saved value on exit if it is still false.
	(gimplify_vla_decl): Do not set gimplify_ctxp->save_stack here.
	(gimplify_call_expr) <BUILT_IN_ALLOCA[_WITH_ALIGN]>: New case.  Set
	either save_stack or keep_stack depending on CALL_ALLOCA_FOR_VAR_P.
	* doc/extend.texi (Variable Length): Document new behavior.
	* doc/generic.texi (Blocks): Document new handling of VLAs.

From-SVN: r231260
This commit is contained in:
Eric Botcazou 2015-12-04 11:57:15 +00:00 committed by Eric Botcazou
parent a3eb8a52b5
commit 03c0079882
6 changed files with 88 additions and 18 deletions

View File

@ -1,3 +1,18 @@
2015-12-04 Eric Botcazou <ebotcazou@adacore.com>
PR middle-end/65958
* gimplify.c (struct gimplify_ctx): Turn boolean fields into 1-bit
fields, add keep_stack and reorder them.
(gimplify_bind_expr): Save gimplify_ctxp->keep_stack on entry then
set it to false. Do not insert a stack save/restore pair if it has
been set to true by the gimplification of the statements.
Restore it to the saved value on exit if it is still false.
(gimplify_vla_decl): Do not set gimplify_ctxp->save_stack here.
(gimplify_call_expr) <BUILT_IN_ALLOCA[_WITH_ALIGN]>: New case. Set
either save_stack or keep_stack depending on CALL_ALLOCA_FOR_VAR_P.
* doc/extend.texi (Variable Length): Document new behavior.
* doc/generic.texi (Blocks): Document new handling of VLAs.
2015-12-04 Eric Botcazou <ebotcazou@adacore.com>
Tristan Gingold <gingold@adacore.com>

View File

@ -1658,9 +1658,7 @@ variable-length arrays are more elegant.
There are other differences between these two methods. Space allocated
with @code{alloca} exists until the containing @emph{function} returns.
The space for a variable-length array is deallocated as soon as the array
name's scope ends. (If you use both variable-length arrays and
@code{alloca} in the same function, deallocation of a variable-length array
also deallocates anything more recently allocated with @code{alloca}.)
name's scope ends, unless you also use @code{alloca} in this scope.
You can also use variable-length arrays as arguments to functions:

View File

@ -1950,11 +1950,15 @@ this initialization replaces the @code{DECL_STMT}. These variables
will never require cleanups. The scope of these variables is just the
body
Variable-length arrays (VLAs) complicate this process, as their
size often refers to variables initialized earlier in the block.
To handle this, we currently split the block at that point, and
move the VLA into a new, inner @code{BIND_EXPR}. This strategy
may change in the future.
Variable-length arrays (VLAs) complicate this process, as their size
often refers to variables initialized earlier in the block and their
initialization involves an explicit stack allocation. To handle this,
we add an indirection and replace them with a pointer to stack space
allocated by means of @code{alloca}. In most cases, we also arrange
for this space to be reclaimed when the enclosing @code{BIND_EXPR} is
exited, the exception to this being when there is an explicit call to
@code{alloca} in the source code, in which case the stack is left
depressed on exit of the @code{BIND_EXPR}.
A C++ program will usually contain more @code{BIND_EXPR}s than
there are syntactic blocks in the source code, since several C++

View File

@ -155,10 +155,11 @@ struct gimplify_ctx
hash_table<gimplify_hasher> *temp_htab;
int conditions;
bool save_stack;
bool into_ssa;
bool allow_rhs_cond_expr;
bool in_cleanup_point_expr;
unsigned into_ssa : 1;
unsigned allow_rhs_cond_expr : 1;
unsigned in_cleanup_point_expr : 1;
unsigned keep_stack : 1;
unsigned save_stack : 1;
};
struct gimplify_omp_ctx
@ -1080,6 +1081,7 @@ static enum gimplify_status
gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
{
tree bind_expr = *expr_p;
bool old_keep_stack = gimplify_ctxp->keep_stack;
bool old_save_stack = gimplify_ctxp->save_stack;
tree t;
gbind *bind_stmt;
@ -1129,9 +1131,10 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
}
bind_stmt = gimple_build_bind (BIND_EXPR_VARS (bind_expr), NULL,
BIND_EXPR_BLOCK (bind_expr));
BIND_EXPR_BLOCK (bind_expr));
gimple_push_bind_expr (bind_stmt);
gimplify_ctxp->keep_stack = false;
gimplify_ctxp->save_stack = false;
/* Gimplify the body into the GIMPLE_BIND tuple's body. */
@ -1154,7 +1157,10 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
cleanup = NULL;
stack_save = NULL;
if (gimplify_ctxp->save_stack)
/* If the code both contains VLAs and calls alloca, then we cannot reclaim
the stack space allocated to the VLAs. */
if (gimplify_ctxp->save_stack && !gimplify_ctxp->keep_stack)
{
gcall *stack_restore;
@ -1236,7 +1242,11 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
gimple_bind_set_body (bind_stmt, new_body);
}
/* keep_stack propagates all the way up to the outermost BIND_EXPR. */
if (!gimplify_ctxp->keep_stack)
gimplify_ctxp->keep_stack = old_keep_stack;
gimplify_ctxp->save_stack = old_save_stack;
gimple_pop_bind_expr ();
gimplify_seq_add_stmt (pre_p, bind_stmt);
@ -1393,10 +1403,6 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
t = build2 (MODIFY_EXPR, TREE_TYPE (addr), addr, t);
gimplify_and_add (t, seq_p);
/* Indicate that we need to restore the stack level when the
enclosing BIND_EXPR is exited. */
gimplify_ctxp->save_stack = true;
}
/* A helper function to be called via walk_tree. Mark all labels under *TP
@ -2377,6 +2383,18 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
&& DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
switch (DECL_FUNCTION_CODE (fndecl))
{
case BUILT_IN_ALLOCA:
case BUILT_IN_ALLOCA_WITH_ALIGN:
/* If the call has been built for a variable-sized object, then we
want to restore the stack level when the enclosing BIND_EXPR is
exited to reclaim the allocated space; otherwise, we precisely
need to do the opposite and preserve the latest stack level. */
if (CALL_ALLOCA_FOR_VAR_P (*expr_p))
gimplify_ctxp->save_stack = true;
else
gimplify_ctxp->keep_stack = true;
break;
case BUILT_IN_VA_START:
{
builtin_va_start_p = TRUE;

View File

@ -1,3 +1,7 @@
2015-12-04 Eric Botcazou <ebotcazou@adacore.com>
* gcc.dg/vla-24.c: New test.
2015-12-04 Eric Botcazou <ebotcazou@adacore.com>
* gcc.target/aarch64/stack-checking.c: New test.

View File

@ -0,0 +1,31 @@
/* PR middle-end/65958 */
/* { dg-do run } */
/* { dg-options "-std=gnu99" } */
extern void abort (void);
int foo (int n)
{
char *p, *q;
if (1)
{
char i[n];
p = __builtin_alloca (8);
p[0] = 1;
}
q = __builtin_alloca (64);
__builtin_memset (q, 0, 64);
return !p[0];
}
int main (void)
{
if (foo (48) != 0)
abort ();
return 0;
}