This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PR c++/84263] GC ICE with decltype


This patch fixes 84263, a GC breakage entirely unconnected with the patch of mine that exposed it. I guess I perturbed the memory layout sufficiently to tickle it -- on a 32bit host.

The underlying problem is that decltype parsing has to squirrel away some data in the same manner to template-ids. But it was failing to push and pop the deferring access stack. That meant it stashed its own deferred accesses, but they also remained on the stack. A subsequent deferred access could reallocate the vector of accesses there, if a subsequent access needed deferring. That reallocation proceeds by gc_alloc/gc_free. The gc_free frees the original set, which is what we had stashed away. All is well until we try and GC things, with that token still live. Boom!

Fixed by pushing and popping the access stack. I also reorganized the code to use the modern construct of 'if ... else', rather the assembler-level use of a goto!

Martin, I've bootstrapped this on an x86_64 native setup, but i686 native is tricky. Are you able to give this a spin? I modified the testcase slightly -- replacing an 'int' with '__SIZE_TYPE__'.

nathan

--
Nathan Sidwell
2018-02-08  Nathan Sidwell  <nathan@acm.org>

	PR c++/84263
	* parser.c (cp_parser_decltype): Push and pop
	deferring_access_checks.  Reorganize to avoid goto.

	* g++.dg/parse/pr84263.C: New.

Index: cp/parser.c
===================================================================
--- cp/parser.c	(revision 257496)
+++ cp/parser.c	(working copy)
@@ -14049,12 +14049,7 @@ cp_parser_decltype_expr (cp_parser *pars
 static tree
 cp_parser_decltype (cp_parser *parser)
 {
-  tree expr;
   bool id_expression_or_member_access_p = false;
-  const char *saved_message;
-  bool saved_integral_constant_expression_p;
-  bool saved_non_integral_constant_expression_p;
-  bool saved_greater_than_is_operator_p;
   cp_token *start_token = cp_lexer_peek_token (parser->lexer);
 
   if (start_token->type == CPP_DECLTYPE)
@@ -14073,77 +14068,83 @@ cp_parser_decltype (cp_parser *parser)
   if (!parens.require_open (parser))
     return error_mark_node;
 
-  /* decltype (auto) */
+  push_deferring_access_checks (dk_deferred);
+
+  tree expr = NULL_TREE;
+  
   if (cxx_dialect >= cxx14
       && cp_lexer_next_token_is_keyword (parser->lexer, RID_AUTO))
+    /* decltype (auto) */
+    cp_lexer_consume_token (parser->lexer);
+  else
     {
-      cp_lexer_consume_token (parser->lexer);
-      if (!parens.require_close (parser))
-	return error_mark_node;
-      expr = make_decltype_auto ();
-      AUTO_IS_DECLTYPE (expr) = true;
-      goto rewrite;
-    }
+      /* decltype (expression)  */
 
-  /* Types cannot be defined in a `decltype' expression.  Save away the
-     old message.  */
-  saved_message = parser->type_definition_forbidden_message;
-
-  /* And create the new one.  */
-  parser->type_definition_forbidden_message
-    = G_("types may not be defined in %<decltype%> expressions");
-
-  /* The restrictions on constant-expressions do not apply inside
-     decltype expressions.  */
-  saved_integral_constant_expression_p
-    = parser->integral_constant_expression_p;
-  saved_non_integral_constant_expression_p
-    = parser->non_integral_constant_expression_p;
-  parser->integral_constant_expression_p = false;
-
-  /* Within a parenthesized expression, a `>' token is always
-     the greater-than operator.  */
-  saved_greater_than_is_operator_p
-    = parser->greater_than_is_operator_p;
-  parser->greater_than_is_operator_p = true;
-
-  /* Do not actually evaluate the expression.  */
-  ++cp_unevaluated_operand;
-
-  /* Do not warn about problems with the expression.  */
-  ++c_inhibit_evaluation_warnings;
-
-  expr = cp_parser_decltype_expr (parser, id_expression_or_member_access_p);
-
-  /* Go back to evaluating expressions.  */
-  --cp_unevaluated_operand;
-  --c_inhibit_evaluation_warnings;
-
-  /* The `>' token might be the end of a template-id or
-     template-parameter-list now.  */
-  parser->greater_than_is_operator_p
-    = saved_greater_than_is_operator_p;
-
-  /* Restore the old message and the integral constant expression
-     flags.  */
-  parser->type_definition_forbidden_message = saved_message;
-  parser->integral_constant_expression_p
-    = saved_integral_constant_expression_p;
-  parser->non_integral_constant_expression_p
-    = saved_non_integral_constant_expression_p;
+      /* Types cannot be defined in a `decltype' expression.  Save away the
+	 old message and set the new one.  */
+      const char *saved_message = parser->type_definition_forbidden_message;
+      parser->type_definition_forbidden_message
+	= G_("types may not be defined in %<decltype%> expressions");
+
+      /* The restrictions on constant-expressions do not apply inside
+	 decltype expressions.  */
+      bool saved_integral_constant_expression_p
+	= parser->integral_constant_expression_p;
+      bool saved_non_integral_constant_expression_p
+	= parser->non_integral_constant_expression_p;
+      parser->integral_constant_expression_p = false;
+
+      /* Within a parenthesized expression, a `>' token is always
+	 the greater-than operator.  */
+      bool saved_greater_than_is_operator_p
+	= parser->greater_than_is_operator_p;
+      parser->greater_than_is_operator_p = true;
+
+      /* Do not actually evaluate the expression.  */
+      ++cp_unevaluated_operand;
+
+      /* Do not warn about problems with the expression.  */
+      ++c_inhibit_evaluation_warnings;
+
+      expr = cp_parser_decltype_expr (parser, id_expression_or_member_access_p);
+
+      /* Go back to evaluating expressions.  */
+      --cp_unevaluated_operand;
+      --c_inhibit_evaluation_warnings;
+
+      /* The `>' token might be the end of a template-id or
+	 template-parameter-list now.  */
+      parser->greater_than_is_operator_p
+	= saved_greater_than_is_operator_p;
+
+      /* Restore the old message and the integral constant expression
+	 flags.  */
+      parser->type_definition_forbidden_message = saved_message;
+      parser->integral_constant_expression_p
+	= saved_integral_constant_expression_p;
+      parser->non_integral_constant_expression_p
+	= saved_non_integral_constant_expression_p;
+    }
 
   /* Parse to the closing `)'.  */
   if (!parens.require_close (parser))
     {
       cp_parser_skip_to_closing_parenthesis (parser, true, false,
 					     /*consume_paren=*/true);
+      pop_deferring_access_checks ();
       return error_mark_node;
     }
 
-  expr = finish_decltype_type (expr, id_expression_or_member_access_p,
-			       tf_warning_or_error);
+  if (!expr)
+    {
+      /* Build auto.  */
+      expr = make_decltype_auto ();
+      AUTO_IS_DECLTYPE (expr) = true;
+    }
+  else
+    expr = finish_decltype_type (expr, id_expression_or_member_access_p,
+				 tf_warning_or_error);
 
- rewrite:
   /* Replace the decltype with a CPP_DECLTYPE so we don't need to parse
      it again.  */
   start_token->type = CPP_DECLTYPE;
@@ -14153,6 +14154,8 @@ cp_parser_decltype (cp_parser *parser)
   start_token->keyword = RID_MAX;
   cp_lexer_purge_tokens_after (parser->lexer, start_token);
 
+  pop_to_parent_deferring_access_checks ();
+  
   return expr;
 }
 
Index: testsuite/g++.dg/parse/pr84263.C
===================================================================
--- testsuite/g++.dg/parse/pr84263.C	(revision 0)
+++ testsuite/g++.dg/parse/pr84263.C	(working copy)
@@ -0,0 +1,36 @@
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "--param ggc-min-expand=0 --param ggc-min-heapsize=0" }
+// PR 84263, a GC bug exposed on i686 native compiler (and possibly
+// other 32-bit hosts).  decltype parsing could create a 
+// pointer that would be gc-freed by later actions.
+
+namespace std {
+template <typename a> struct b {
+  int c;
+  a d;
+};
+template <typename> class g;
+template <class> class initializer_list {
+  void *e;
+  __SIZE_TYPE__ f;
+};
+class h;
+class j {
+  typedef b<h> i;
+
+public:
+  j();
+  j(initializer_list<i>);
+};
+template <typename> struct m;
+template <int k> struct m<char[k]> {};
+class h {
+public:
+  template <typename l> h(l &);
+};
+class G {
+  G();
+  j n;
+};
+G::G() { n = decltype(n){{0, ""}, {1, ".unoLineArrowEnd"}}; }
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]