]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/types2: report error for incomplete struct composite literal...
authorRobert Griesemer <gri@golang.org>
Fri, 5 Nov 2021 04:31:08 +0000 (21:31 -0700)
committerRobert Griesemer <gri@golang.org>
Sat, 6 Nov 2021 19:41:15 +0000 (19:41 +0000)
Mark a struct as "complete" with a non-nil (but possibly zero length)
fields list. Add a test when type-checking struct composite literals,
the same way we do for other composite literal types.

Fixes #49276.

Change-Id: If44a3d790bf7032ddcd155af49bdc47b1cdff4fc
Reviewed-on: https://go-review.googlesource.com/c/go/+/361412
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/types2/expr.go
src/cmd/compile/internal/types2/struct.go
src/cmd/compile/internal/types2/subst.go
src/cmd/compile/internal/types2/testdata/fixedbugs/issue49276.go [new file with mode: 0644]

index 95b96f23345aa14f413d1ee9f23e32609d0c6b4d..d618ebd3722683a8f4b72bee806811999ba47856 100644 (file)
@@ -1260,6 +1260,12 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
 
                switch utyp := structure(base).(type) {
                case *Struct:
+                       // Prevent crash if the struct referred to is not yet set up.
+                       // See analogous comment for *Array.
+                       if utyp.fields == nil {
+                               check.error(e, "illegal cycle in type declaration")
+                               goto Error
+                       }
                        if len(e.ElemList) == 0 {
                                break
                        }
index 933d7ef947d2b32025ac53019b7414c40b6bbdf5..8c39f5e3c41fc9adec23534ef891ce0c75b21e06 100644 (file)
@@ -14,7 +14,7 @@ import (
 
 // A Struct represents a struct type.
 type Struct struct {
-       fields []*Var
+       fields []*Var   // fields != nil indicates the struct is set up (possibly with len(fields) == 0)
        tags   []string // field tags; nil if there are no tags
 }
 
@@ -32,7 +32,9 @@ func NewStruct(fields []*Var, tags []string) *Struct {
        if len(tags) > len(fields) {
                panic("more tags than fields")
        }
-       return &Struct{fields: fields, tags: tags}
+       s := &Struct{fields: fields, tags: tags}
+       s.markComplete()
+       return s
 }
 
 // NumFields returns the number of fields in the struct (including blank and embedded fields).
@@ -55,8 +57,15 @@ func (s *Struct) String() string   { return TypeString(s, nil) }
 // ----------------------------------------------------------------------------
 // Implementation
 
+func (s *Struct) markComplete() {
+       if s.fields == nil {
+               s.fields = make([]*Var, 0)
+       }
+}
+
 func (check *Checker) structType(styp *Struct, e *syntax.StructType) {
        if e.FieldList == nil {
+               styp.markComplete()
                return
        }
 
@@ -160,6 +169,7 @@ func (check *Checker) structType(styp *Struct, e *syntax.StructType) {
 
        styp.fields = fields
        styp.tags = tags
+       styp.markComplete()
 }
 
 func embeddedFieldIdent(e syntax.Expr) *syntax.Name {
index 269b284ac4566ad2602e5583a50e4b71d6b7696a..a4e46b209745759ca8a88d7df740ac9d51e2113f 100644 (file)
@@ -91,7 +91,9 @@ func (subst *subster) typ(typ Type) Type {
 
        case *Struct:
                if fields, copied := subst.varList(t.fields); copied {
-                       return &Struct{fields: fields, tags: t.tags}
+                       s := &Struct{fields: fields, tags: t.tags}
+                       s.markComplete()
+                       return s
                }
 
        case *Pointer:
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49276.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49276.go
new file mode 100644 (file)
index 0000000..8839087
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2021 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.
+
+package p
+
+import "unsafe"
+
+type S /* ERROR illegal cycle in declaration of S */ struct {
+       _ [unsafe.Sizeof(s)]byte
+}
+
+var s S
+
+// Since f is a pointer, this case could be valid.
+// But it's pathological and not worth the expense.
+type T struct {
+       f *[unsafe.Sizeof(T /* ERROR illegal cycle in type declaration */ {})]int
+}
+
+// a mutually recursive case using unsafe.Sizeof
+type (
+       A1 struct {
+               _ [unsafe.Sizeof(B1{})]int
+       }
+
+       B1 struct {
+               _ [unsafe.Sizeof(A1 /* ERROR illegal cycle in type declaration */ {})]int
+       }
+)
+
+// a mutually recursive case using len
+type (
+       A2 struct {
+               f [len(B2{}.f)]int
+       }
+
+       B2 struct {
+               f [len(A2 /* ERROR illegal cycle in type declaration */ {}.f)]int
+       }
+)
+
+// test case from issue
+type a struct {
+       _ [42 - unsafe.Sizeof(a /* ERROR illegal cycle in type declaration */ {})]byte
+}