]> Cypherpunks repositories - gostls13.git/commitdiff
go/internal/gccgoimporter: fix bug reading V1 export data
authorThan McIntosh <thanm@google.com>
Fri, 30 Nov 2018 14:50:05 +0000 (09:50 -0500)
committerThan McIntosh <thanm@google.com>
Fri, 30 Nov 2018 20:00:49 +0000 (20:00 +0000)
Fix a bug in the reading of elderly export data. In such export data
when reading type information it's possible to encounter a named type N1
defined as a typedef of some other named type N2 at a point when the
underying type of N1 has not yet been finalized. Handle this case by
generating a fixup, then process fixups at the end of parsing to
set the correct underlying type.

Fixes #29006.

Change-Id: I6a505c897bd95eb161ee04637bb6eebad9f20d52
Reviewed-on: https://go-review.googlesource.com/c/151997
Run-TryBot: Than McIntosh <thanm@google.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/go/internal/gccgoimporter/importer_test.go
src/go/internal/gccgoimporter/parser.go
src/go/internal/gccgoimporter/testdata/v1reflect.gox [new file with mode: 0644]

index 96505b2bab62bceb4f1b3d60cbf5192a471fd20b..30b51db9d4d0a58c5b8b0db723924ce0b686ed88 100644 (file)
@@ -86,6 +86,7 @@ var importerTests = [...]importerTest{
        {pkgpath: "aliases", name: "C0", want: "type C0 struct{f1 C1; f2 C1}"},
        {pkgpath: "escapeinfo", name: "NewT", want: "func NewT(data []byte) *T"},
        {pkgpath: "issue27856", name: "M", want: "type M struct{E F}"},
+       {pkgpath: "v1reflect", name: "Type", want: "type Type interface{Align() int; AssignableTo(u Type) bool; Bits() int; ChanDir() ChanDir; Elem() Type; Field(i int) StructField; FieldAlign() int; FieldByIndex(index []int) StructField; FieldByName(name string) (StructField, bool); FieldByNameFunc(match func(string) bool) (StructField, bool); Implements(u Type) bool; In(i int) Type; IsVariadic() bool; Key() Type; Kind() Kind; Len() int; Method(int) Method; MethodByName(string) (Method, bool); Name() string; NumField() int; NumIn() int; NumMethod() int; NumOut() int; Out(i int) Type; PkgPath() string; Size() uintptr; String() string; common() *commonType; rawString() string; runtimeType() *runtimeType; uncommon() *uncommonType}"},
 }
 
 func TestGoxImporter(t *testing.T) {
index e75f15c429f4d8c28cae8493b530f3a22a786be5..7d075db4cef62a7cbff8eb9c5d4aa960c03a1b4d 100644 (file)
@@ -29,9 +29,30 @@ type parser struct {
        imports  map[string]*types.Package // package path -> package object
        typeList []types.Type              // type number -> type
        typeData []string                  // unparsed type data (v3 and later)
+       fixups   []fixupRecord             // fixups to apply at end of parsing
        initdata InitData                  // package init priority data
 }
 
+// When reading V1 export data it's possible to encounter a defined
+// type N1 with an underlying defined type N2 while we are still
+// reading in that defined type N2; see issue #29006 for an instance
+// of this. Example:
+//
+//   type N1 N2
+//   type N2 struct {
+//      ...
+//      p *N1
+//   }
+//
+// To handle such cases, the parser generates a fixup record (below) and
+// delays setting of N1's underlying type until parsing is complete, at
+// which point fixups are applied.
+
+type fixupRecord struct {
+       toUpdate *types.Named // type to modify when fixup is processed
+       target   types.Type   // type that was incomplete when fixup was created
+}
+
 func (p *parser) init(filename string, src io.Reader, imports map[string]*types.Package) {
        p.scanner = new(scanner.Scanner)
        p.initScanner(filename, src)
@@ -504,7 +525,15 @@ func (p *parser) parseNamedType(nlist []int) types.Type {
 
        underlying := p.parseType(pkg)
        if nt.Underlying() == nil {
-               nt.SetUnderlying(underlying.Underlying())
+               if underlying.Underlying() == nil {
+                       if p.version != "v1" {
+                               p.errorf("internal error: unexpected fixup required for %v", nt)
+                       }
+                       fix := fixupRecord{toUpdate: nt, target: underlying}
+                       p.fixups = append(p.fixups, fix)
+               } else {
+                       nt.SetUnderlying(underlying.Underlying())
+               }
        }
 
        if p.tok == '\n' {
@@ -1175,6 +1204,13 @@ func (p *parser) parsePackage() *types.Package {
        for p.tok != scanner.EOF {
                p.parseDirective()
        }
+       for _, f := range p.fixups {
+               if f.target.Underlying() == nil {
+                       p.errorf("internal error: fixup can't be applied, loop required")
+               }
+               f.toUpdate.SetUnderlying(f.target.Underlying())
+       }
+       p.fixups = nil
        for _, typ := range p.typeList {
                if it, ok := typ.(*types.Interface); ok {
                        it.Complete()
diff --git a/src/go/internal/gccgoimporter/testdata/v1reflect.gox b/src/go/internal/gccgoimporter/testdata/v1reflect.gox
new file mode 100644 (file)
index 0000000..ea46841
Binary files /dev/null and b/src/go/internal/gccgoimporter/testdata/v1reflect.gox differ