]> Cypherpunks repositories - gostls13.git/commitdiff
gc: fix infinite recursion for embedded interfaces
authorLuuk van Dijk <lvd@golang.org>
Tue, 17 Jan 2012 09:00:57 +0000 (10:00 +0100)
committerLuuk van Dijk <lvd@golang.org>
Tue, 17 Jan 2012 09:00:57 +0000 (10:00 +0100)
Fixes #1909

R=rsc, gri
CC=golang-dev
https://golang.org/cl/5523047

src/cmd/gc/dcl.c
src/cmd/gc/export.c
src/cmd/gc/fmt.c
src/cmd/gc/go.y
src/pkg/exp/types/gcimporter.go
test/fixedbugs/bug395.go [new file with mode: 0644]

index 87dab3eecadf9d50ad929497fcdcd75b3a66b82e..94258a0c593d5f72c484f4dd5c7aaf98e4717a6d 100644 (file)
@@ -940,12 +940,20 @@ interfacefield(Node *n)
 Type*
 tointerface(NodeList *l)
 {
-       Type *t, *f, **tp, *t1;
+       Type *t, *f, **tp, **otp, *t1;
 
        t = typ(TINTER);
+       t->orig = typ(TINTER);
 
-       for(tp = &t->type; l; l=l->next) {
+       tp = &t->type;
+       otp = &t->orig->type;
+
+       for(; l; l=l->next) {
                f = interfacefield(l->n);
+               *otp = typ(TFIELD);
+               **otp = *f;
+               otp = &(*otp)->down;
+
                if (l->n->left == N && f->type->etype == TINTER) {
                        // embedded interface, inline methods
                        for(t1=f->type->type; t1; t1=t1->down) {
@@ -953,6 +961,7 @@ tointerface(NodeList *l)
                                f->type = t1->type;
                                f->broke = t1->broke;
                                f->sym = t1->sym;
+                               f->embedded = 1;
                                if(f->sym)
                                        f->nname = newname(f->sym);
                                *tp = f;
index e1f289200ca4a4bc998ad866146203a21f2d6d52..965b745a802346220dbac9f3f1326d4b52e4e368 100644 (file)
@@ -241,6 +241,13 @@ dumpexporttype(Type *t)
        if(t->sym != S && t->etype != TFIELD)
                dumppkg(t->sym->pkg);
 
+       // fmt will print the ->orig of an interface, which has the original embedded interfaces.
+       // be sure to dump them here
+       if(t->etype == TINTER)
+               for(f=t->orig->type; f; f=f->down)
+                       if(f->sym == S)
+                               dumpexporttype(f->type);
+
        dumpexporttype(t->type);
        dumpexporttype(t->down);
 
@@ -470,8 +477,8 @@ importtype(Type *pt, Type *t)
                pt->sym->lastlineno = parserline();
                declare(n, PEXTERN);
                checkwidth(pt);
-       } else if(!eqtype(pt->orig, t))
-               yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt->orig, t);
+       } else if(!eqtype(pt->orig, t->orig))
+               yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt, t);
 
        if(debug['E'])
                print("import type %T %lT\n", pt, t);
index 4afd6c42bfbe91202438d42b2496b5c170a91b0f..09e73c7b926019fc03bfd7de1e7b6ee43c2786a4 100644 (file)
@@ -195,6 +195,7 @@ goopnames[] =
        [OCONTINUE]     = "continue",
        [OCOPY]         = "copy",
        [ODEC]          = "--",
+       [ODELETE]       = "delete",
        [ODEFER]        = "defer",
        [ODIV]          = "/",
        [OEQ]           = "==",
@@ -639,9 +640,15 @@ typefmt(Fmt *fp, Type *t)
                return fmtprint(fp, "map[%T]%T", t->down, t->type);
 
        case TINTER:
+               t = t->orig;
                fmtstrcpy(fp, "interface {");
                for(t1=t->type; t1!=T; t1=t1->down)
-                       if(exportname(t1->sym->name)) {
+                       if(!t1->sym) {
+                               if(t1->down)
+                                       fmtprint(fp, " %T;", t1->type);
+                               else
+                                       fmtprint(fp, " %T ", t1->type);
+                       } else if(exportname(t1->sym->name)) {
                                if(t1->down)
                                        fmtprint(fp, " %hS%hT;", t1->sym, t1->type);
                                else
@@ -946,6 +953,7 @@ static int opprec[] = {
        [OCONVNOP] = 8,
        [OCONV] = 8,
        [OCOPY] = 8,
+       [ODELETE] = 8,
        [OLEN] = 8,
        [OLITERAL] = 8,
        [OMAKESLICE] = 8,
@@ -1010,6 +1018,7 @@ static int opprec[] = {
        [OGT] = 4,
        [ONE] = 4,
        [OCMPSTR] = 4,
+       [OCMPIFACE] = 4,
 
        [OSEND] = 3,
        [OANDAND] = 2,
@@ -1218,6 +1227,7 @@ exprfmt(Fmt *f, Node *n, int prec)
        case OAPPEND:
        case OCAP:
        case OCLOSE:
+       case ODELETE:
        case OLEN:
        case OMAKE:
        case ONEW:
@@ -1288,6 +1298,7 @@ exprfmt(Fmt *f, Node *n, int prec)
                return 0;
 
        case OCMPSTR:
+       case OCMPIFACE:
                exprfmt(f, n->left, nprec);
                fmtprint(f, " %#O ", n->etype);
                exprfmt(f, n->right, nprec+1);
@@ -1303,8 +1314,10 @@ nodefmt(Fmt *f, Node *n)
        Type *t;
 
        t = n->type;
-       if(n->orig == N)
+       if(n->orig == N) {
+               n->orig = n;
                fatal("node with no orig %N", n);
+       }
 
        // we almost always want the original, except in export mode for literals
        // this saves the importer some work, and avoids us having to redo some
@@ -1359,6 +1372,7 @@ nodedump(Fmt *fp, Node *n)
                        indent(fp);
                }
        }
+               fmtprint(fp, "[%p]", n);
 
        switch(n->op) {
        default:
index 6a99a275ca6efe19a2794fa6454836c38d7a14e1..de0735425022f43cd69614689a8524bcca0e5db0 100644 (file)
@@ -1620,7 +1620,7 @@ non_dcl_stmt:
                $$->list = $2;
                if($$->list == nil && curfn != N) {
                        NodeList *l;
-                       
+
                        for(l=curfn->dcl; l; l=l->next) {
                                if(l->n->class == PPARAM)
                                        continue;
@@ -1953,6 +1953,10 @@ hidden_interfacedcl:
        {
                $$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5)));
        }
+|      hidden_type
+       {
+               $$ = nod(ODCLFIELD, N, typenod($1));
+       }
 
 ohidden_funres:
        {
index 10c56db21ff0d78fe2e1a0d850d6a72e5be51a32..a573fbb2463edc4f7741cd041263df37fdc8e9f3 100644 (file)
@@ -460,29 +460,32 @@ func (p *gcParser) parseSignature() *Func {
        return &Func{Params: params, Results: results, IsVariadic: isVariadic}
 }
 
-// MethodSpec = ( identifier | ExportedName )  Signature .
+// MethodOrEmbedSpec = Name [ Signature ] .
 //
-func (p *gcParser) parseMethodSpec() *ast.Object {
-       if p.tok == scanner.Ident {
-               p.expect(scanner.Ident)
-       } else {
-               p.parseExportedName()
+func (p *gcParser) parseMethodOrEmbedSpec() *ast.Object {
+       p.parseName()
+       if p.tok == '(' {
+               p.parseSignature()
+               // TODO(gri) compute method object
+               return ast.NewObj(ast.Fun, "_")
        }
-       p.parseSignature()
-
-       // TODO(gri) compute method object
-       return ast.NewObj(ast.Fun, "_")
+       // TODO lookup name and return that type
+       return ast.NewObj(ast.Typ, "_")
 }
 
-// InterfaceType = "interface" "{" [ MethodList ] "}" .
-// MethodList    = MethodSpec { ";" MethodSpec } .
+// InterfaceType = "interface" "{" [ MethodOrEmbedList ] "}" .
+// MethodOrEmbedList = MethodOrEmbedSpec { ";" MethodOrEmbedSpec } .
 //
 func (p *gcParser) parseInterfaceType() Type {
        var methods ObjList
 
        parseMethod := func() {
-               meth := p.parseMethodSpec()
-               methods = append(methods, meth)
+               switch m := p.parseMethodOrEmbedSpec(); m.Kind {
+               case ast.Typ:
+                       // TODO expand embedded methods
+               case ast.Fun:
+                       methods = append(methods, m)
+               }
        }
 
        p.expectKeyword("interface")
diff --git a/test/fixedbugs/bug395.go b/test/fixedbugs/bug395.go
new file mode 100644 (file)
index 0000000..d0af3f9
--- /dev/null
@@ -0,0 +1,15 @@
+// $G $D/$F.go || echo "Bug395"
+
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 1909
+// Would OOM due to exponential recursion on Foo's expanded methodset in nodefmt
+package test
+
+type Foo interface {
+       Bar() interface{Foo}
+       Baz() interface{Foo}
+       Bug() interface{Foo}
+}