Fix obstack use-after-free problems in C frontend, PR69522
authorBernd Schmidt <bernds@redhat.com>
Fri, 12 Feb 2016 01:38:06 +0000 (01:38 +0000)
committerBernd Schmidt <bernds@gcc.gnu.org>
Fri, 12 Feb 2016 01:38:06 +0000 (01:38 +0000)
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

gcc/c/ChangeLog
gcc/c/c-parser.c
gcc/c/c-tree.h
gcc/c/c-typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/pr69522.c [new file with mode: 0644]

index b595b81..dda2216 100644 (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
index eede3a7..7a27244 100644 (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);
 
index cf79ba7..96ab049 100644 (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 *);
index 82efacf..1122a88 100644 (file)
@@ -7548,6 +7548,30 @@ really_start_incremental_init (tree type)
     }
 }
 \f
+/* 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))
index 5fcd863..cd3161f 100644 (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
diff --git a/gcc/testsuite/gcc.dg/pr69522.c b/gcc/testsuite/gcc.dg/pr69522.c
new file mode 100644 (file)
index 0000000..452a1ae
--- /dev/null
@@ -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}};