From: Robert Griesemer Date: Sat, 13 Nov 2021 02:24:54 +0000 (-0800) Subject: cmd/compile/internal/types2: simplify under() and fix a crash X-Git-Tag: go1.18beta1~329 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=c2397905e027cdbab3a28d02813adcb82368422c;p=gostls13.git cmd/compile/internal/types2: simplify under() and fix a crash 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 Reviewed-by: Robert Findley --- diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go index fbfe3c81ff..b4035e16b3 100644 --- a/src/cmd/compile/internal/types2/lookup.go +++ b/src/cmd/compile/internal/types2/lookup.go @@ -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 diff --git a/src/cmd/compile/internal/types2/testdata/check/cycles.src b/src/cmd/compile/internal/types2/testdata/check/cycles.src index b2ee8ecd5f..998f9f7da9 100644 --- a/src/cmd/compile/internal/types2/testdata/check/cycles.src +++ b/src/cmd/compile/internal/types2/testdata/check/cycles.src @@ -45,6 +45,7 @@ type ( // pointers P0 *P0 + PP *struct{ PP.f /* ERROR no field or method f */ } // functions F0 func(F0) diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 7fcb196c5a..af195c08a4 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -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. diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index e22b1ff0a0..e077879b9d 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -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