diff options
author | bernds <bernds@138bc75d-0d04-0410-961f-82ee72b054a4> | 2016-02-12 01:38:06 +0000 |
---|---|---|
committer | bernds <bernds@138bc75d-0d04-0410-961f-82ee72b054a4> | 2016-02-12 01:38:06 +0000 |
commit | 74a4140fabf2cbfc7adfb545468e07a427243690 (patch) | |
tree | 91eedf26ad1b6621eed02ddc3ccecc0614c40a1a /gcc/c | |
parent | 9ddb20d61efab00d2e84255959e283aefd31f5e0 (diff) | |
download | gcc-74a4140fabf2cbfc7adfb545468e07a427243690.tar.gz |
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@233366 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/c')
-rw-r--r-- | gcc/c/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/c/c-parser.c | 18 | ||||
-rw-r--r-- | gcc/c/c-tree.h | 1 | ||||
-rw-r--r-- | gcc/c/c-typeck.c | 53 |
4 files changed, 51 insertions, 33 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index b595b81676d..dda2216abb9 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -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 diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index eede3a745fa..7a272447900 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -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); diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index cf79ba71b15..96ab049b982 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -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 *); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 82efacf1389..1122a88417b 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -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)) |