]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile/internal/types2: simplify under() and fix a crash
authorRobert Griesemer <gri@golang.org>
Sat, 13 Nov 2021 02:24:54 +0000 (18:24 -0800)
committerRobert Griesemer <gri@golang.org>
Sat, 13 Nov 2021 03:33:55 +0000 (03:33 +0000)
The simplified version of under exposed a bug (by crashing):
When a pointer base is used before the pointer is fully set
up, the base is nil. Set the pointer base to Typ[Invalid]
when creating the pointer, and add an extra safety check
into deref. Reviewed all code that creates pointers.

The same error cannot happen with other types because
accessing parts of another type results in an expression
that is not a type, and thus these kids of cycles cannot
happen.

Change-Id: I8332a281a534c094cfbb3623a636960865813ff6
Reviewed-on: https://go-review.googlesource.com/c/go/+/363665
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/types2/lookup.go
src/cmd/compile/internal/types2/testdata/check/cycles.src
src/cmd/compile/internal/types2/type.go
src/cmd/compile/internal/types2/typexpr.go

index fbfe3c81ffa8a14421749683cef347e062531137..b4035e16b3dde560d8aa70c8a56a4d4cd91cf681 100644 (file)
@@ -491,6 +491,13 @@ func (check *Checker) assertableTo(V *Interface, T Type) (method, wrongType *Fun
 // Otherwise it returns (typ, false).
 func deref(typ Type) (Type, bool) {
        if p, _ := typ.(*Pointer); p != nil {
+               // p.base should never be nil, but be conservative
+               if p.base == nil {
+                       if debug {
+                               panic("pointer with nil base type (possibly due to an invalid cyclic declaration)")
+                       }
+                       return Typ[Invalid], true
+               }
                return p.base, true
        }
        return typ, false
index b2ee8ecd5f6001076e336779a9b5150c1e524162..998f9f7da980116ccbae32f6fb796766fe4c19fa 100644 (file)
@@ -45,6 +45,7 @@ type (
 
        // pointers
        P0 *P0
+       PP *struct{ PP.f /* ERROR no field or method f */ }
 
        // functions
        F0 func(F0)
index 7fcb196c5acf8295dccffba352e6ec46386d6041..af195c08a41d2606f9e11bc924d2fdc773fcfd41 100644 (file)
@@ -21,13 +21,10 @@ type Type interface {
 // under must only be called when a type is known
 // to be fully set up.
 func under(t Type) Type {
-       switch t := t.(type) {
-       case *Named:
+       if t, _ := t.(*Named); t != nil {
                return t.under()
-       case *TypeParam:
-               return t.iface()
        }
-       return t
+       return t.Underlying()
 }
 
 // If x and y are identical, match returns x.
index e22b1ff0a0b2fc62287bff67c18817dec2ca8905..e077879b9da432c4939a7162845b365dbfb58f91 100644 (file)
@@ -315,6 +315,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
        case *syntax.Operation:
                if e.Op == syntax.Mul && e.Y == nil {
                        typ := new(Pointer)
+                       typ.base = Typ[Invalid] // avoid nil base in invalid recursive type declaration
                        def.setUnderlying(typ)
                        typ.base = check.varType(e.X)
                        // If typ.base is invalid, it's unlikely that *base is particularly