Fix obstack use-after-free problems in C frontend, PR69522

c/
	PR c/69522
	* c-parser.c (c_parser_braced_init): New arg outer_obstack.  All
	callers changed.  If nested_p is true, use it to call
	finish_implicit_inits.
	* c-tree.h (finish_implicit_inits): Declare.
	* c-typeck.c (finish_implicit_inits): New function.  Move code
	from ...
	(push_init_level): ... here.
	(set_designator, process_init_element): Call finish_implicit_inits.

testsuite/
	PR c/69522
	gcc.dg/pr69522.c: New test.

From-SVN: r233366
This commit is contained in:
Bernd Schmidt 2016-02-12 01:38:06 +00:00 committed by Bernd Schmidt
parent 38d795d27c
commit 16595a1f28
6 changed files with 65 additions and 33 deletions

View File

@ -1,3 +1,15 @@
2016-02-12 Bernd Schmidt <bschmidt@redhat.com>
PR c/69522
* c-parser.c (c_parser_braced_init): New arg outer_obstack. All
callers changed. If nested_p is true, use it to call
finish_implicit_inits.
* c-tree.h (finish_implicit_inits): Declare.
* c-typeck.c (finish_implicit_inits): New function. Move code
from ...
(push_init_level): ... here.
(set_designator, process_init_element): Call finish_implicit_inits.
2016-02-11 Jakub Jelinek <jakub@redhat.com>
PR c/69768

View File

@ -1293,7 +1293,8 @@ static tree c_parser_simple_asm_expr (c_parser *);
static tree c_parser_attributes (c_parser *);
static struct c_type_name *c_parser_type_name (c_parser *);
static struct c_expr c_parser_initializer (c_parser *);
static struct c_expr c_parser_braced_init (c_parser *, tree, bool);
static struct c_expr c_parser_braced_init (c_parser *, tree, bool,
struct obstack *);
static void c_parser_initelt (c_parser *, struct obstack *);
static void c_parser_initval (c_parser *, struct c_expr *,
struct obstack *);
@ -4307,7 +4308,7 @@ static struct c_expr
c_parser_initializer (c_parser *parser)
{
if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
return c_parser_braced_init (parser, NULL_TREE, false);
return c_parser_braced_init (parser, NULL_TREE, false, NULL);
else
{
struct c_expr ret;
@ -4327,7 +4328,8 @@ c_parser_initializer (c_parser *parser)
top-level initializer in a declaration. */
static struct c_expr
c_parser_braced_init (c_parser *parser, tree type, bool nested_p)
c_parser_braced_init (c_parser *parser, tree type, bool nested_p,
struct obstack *outer_obstack)
{
struct c_expr ret;
struct obstack braced_init_obstack;
@ -4336,7 +4338,10 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p)
gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE));
c_parser_consume_token (parser);
if (nested_p)
push_init_level (brace_loc, 0, &braced_init_obstack);
{
finish_implicit_inits (brace_loc, outer_obstack);
push_init_level (brace_loc, 0, &braced_init_obstack);
}
else
really_start_incremental_init (type);
if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
@ -4594,7 +4599,8 @@ c_parser_initval (c_parser *parser, struct c_expr *after,
location_t loc = c_parser_peek_token (parser)->location;
if (c_parser_next_token_is (parser, CPP_OPEN_BRACE) && !after)
init = c_parser_braced_init (parser, NULL_TREE, true);
init = c_parser_braced_init (parser, NULL_TREE, true,
braced_init_obstack);
else
{
init = c_parser_expr_no_commas (parser, after);
@ -8083,7 +8089,7 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser,
error_at (type_loc, "compound literal has variable size");
type = error_mark_node;
}
init = c_parser_braced_init (parser, type, false);
init = c_parser_braced_init (parser, type, false, NULL);
finish_init ();
maybe_warn_string_init (type_loc, type, init);

View File

@ -625,6 +625,7 @@ extern void maybe_warn_string_init (location_t, tree, struct c_expr);
extern void start_init (tree, tree, int);
extern void finish_init (void);
extern void really_start_incremental_init (tree);
extern void finish_implicit_inits (location_t, struct obstack *);
extern void push_init_level (location_t, int, struct obstack *);
extern struct c_expr pop_init_level (location_t, int, struct obstack *);
extern void set_init_index (location_t, tree, tree, struct obstack *);

View File

@ -7548,6 +7548,30 @@ really_start_incremental_init (tree type)
}
}
/* Called when we see an open brace for a nested initializer. Finish
off any pending levels with implicit braces. */
void
finish_implicit_inits (location_t loc, struct obstack *braced_init_obstack)
{
while (constructor_stack->implicit)
{
if (RECORD_OR_UNION_TYPE_P (constructor_type)
&& constructor_fields == 0)
process_init_element (input_location,
pop_init_level (loc, 1, braced_init_obstack),
true, braced_init_obstack);
else if (TREE_CODE (constructor_type) == ARRAY_TYPE
&& constructor_max_index
&& tree_int_cst_lt (constructor_max_index,
constructor_index))
process_init_element (input_location,
pop_init_level (loc, 1, braced_init_obstack),
true, braced_init_obstack);
else
break;
}
}
/* Push down into a subobject, for initialization.
If this is for an explicit set of braces, IMPLICIT is 0.
If it is because the next element belongs at a lower level,
@ -7560,33 +7584,6 @@ push_init_level (location_t loc, int implicit,
struct constructor_stack *p;
tree value = NULL_TREE;
/* If we've exhausted any levels that didn't have braces,
pop them now. If implicit == 1, this will have been done in
process_init_element; do not repeat it here because in the case
of excess initializers for an empty aggregate this leads to an
infinite cycle of popping a level and immediately recreating
it. */
if (implicit != 1)
{
while (constructor_stack->implicit)
{
if (RECORD_OR_UNION_TYPE_P (constructor_type)
&& constructor_fields == 0)
process_init_element (input_location,
pop_init_level (loc, 1, braced_init_obstack),
true, braced_init_obstack);
else if (TREE_CODE (constructor_type) == ARRAY_TYPE
&& constructor_max_index
&& tree_int_cst_lt (constructor_max_index,
constructor_index))
process_init_element (input_location,
pop_init_level (loc, 1, braced_init_obstack),
true, braced_init_obstack);
else
break;
}
}
/* Unless this is an explicit brace, we need to preserve previous
content if any. */
if (implicit)
@ -8013,6 +8010,7 @@ set_designator (location_t loc, int array,
}
constructor_designated = 1;
finish_implicit_inits (loc, braced_init_obstack);
push_init_level (loc, 2, braced_init_obstack);
return 0;
}
@ -9396,6 +9394,7 @@ process_init_element (location_t loc, struct c_expr value, bool implicit,
p = p->next;
if (!p)
break;
finish_implicit_inits (loc, braced_init_obstack);
push_init_level (loc, 2, braced_init_obstack);
p->stack = constructor_stack;
if (p->range_end && tree_int_cst_equal (p->index, p->range_end))

View File

@ -1,3 +1,8 @@
2016-02-12 Bernd Schmidt <bschmidt@redhat.com>
PR c/69522
gcc.dg/pr69522.c: New test.
2016-02-12 Patrick Palka <ppalka@gcc.gnu.org>
PR c++/69098

View File

@ -0,0 +1,9 @@
/* { dg-do compile } */
struct str {};
struct {
struct str b;
float c[1];
int d[1];
float e[2];
int f[1];
} a = {{}, 0, {0.5}, 0, 0, {0}};