diff mbox

Go patch committed: Avoid infinite loop in field_reference

Message ID mcrpqqiyrgr.fsf@google.com
State New
Headers show

Commit Message

Ian Lance Taylor Feb. 24, 2011, 4:41 a.m. UTC
This patch to the Go frontend avoids an infinite loop in field_reference
when a struct erroneously attempts to embed itself recursively.
Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Committed to mainline.

Ian
diff mbox

Patch

diff -r f915ffd8b449 -r 6dcd6cfcda1e go/types.cc
--- a/go/types.cc	Wed Feb 23 20:01:54 2011 -0800
+++ b/go/types.cc	Wed Feb 23 20:28:56 2011 -0800
@@ -3583,7 +3583,8 @@ 
 			     source_location location) const
 {
   unsigned int depth;
-  return this->field_reference_depth(struct_expr, name, location, &depth);
+  return this->field_reference_depth(struct_expr, name, location, NULL,
+				     &depth);
 }
 
 // Return an expression for a field, along with the depth at which it
@@ -3593,6 +3594,7 @@ 
 Struct_type::field_reference_depth(Expression* struct_expr,
 				   const std::string& name,
 				   source_location location,
+				   Saw_named_type* saw,
 				   unsigned int* depth) const
 {
   const Struct_field_list* fields = this->fields_;
@@ -3628,13 +3630,41 @@ 
       if (st == NULL)
 	continue;
 
+      Saw_named_type* hold_saw = saw;
+      Saw_named_type saw_here;
+      Named_type* nt = pf->type()->named_type();
+      if (nt == NULL)
+	nt = pf->type()->deref()->named_type();
+      if (nt != NULL)
+	{
+	  Saw_named_type* q;
+	  for (q = saw; q != NULL; q = q->next)
+	    {
+	      if (q->nt == nt)
+		{
+		  // If this is an error, it will be reported
+		  // elsewhere.
+		  break;
+		}
+	    }
+	  if (q != NULL)
+	    continue;
+	  saw_here.next = saw;
+	  saw_here.nt = nt;
+	  saw = &saw_here;
+	}
+
       // Look for a reference using a NULL struct expression.  If we
       // find one, fill in the struct expression with a reference to
       // this field.
       unsigned int subdepth;
       Field_reference_expression* sub = st->field_reference_depth(NULL, name,
 								  location,
+								  saw,
 								  &subdepth);
+
+      saw = hold_saw;
+
       if (sub == NULL)
 	continue;
 
diff -r f915ffd8b449 -r 6dcd6cfcda1e go/types.h
--- a/go/types.h	Wed Feb 23 20:01:54 2011 -0800
+++ b/go/types.h	Wed Feb 23 20:28:56 2011 -0800
@@ -1980,9 +1980,17 @@ 
   do_export(Export*) const;
 
  private:
+  // Used to avoid infinite loops in field_reference_depth.
+  struct Saw_named_type
+  {
+    Saw_named_type* next;
+    Named_type* nt;
+  };
+
   Field_reference_expression*
   field_reference_depth(Expression* struct_expr, const std::string& name,
-			source_location, unsigned int* depth) const;
+			source_location, Saw_named_type*,
+			unsigned int* depth) const;
 
   static Type*
   make_struct_type_descriptor_type();