Skip to content

Commit

Permalink
go/types: don't write during sanitizeInfo if nothing has changed
Browse files Browse the repository at this point in the history
In its final phase, the typechecker walks the types it produces to
ensure that no unexpanded type instances leak through the API. However,
this also walks shared types (such as those in the universe scope),
resulting in a potential data race during concurrent typechecking
passes.

Fix this by being careful not to write if nothing needs to be changed.
Since any shared types should already be sanitized, this should
eliminate data races.

For #44434

Change-Id: Iadb2e78863efe0e974e69a00e255f26cfaf9386a
Reviewed-on: https://go-review.googlesource.com/c/go/+/294411
Trust: Robert Findley <rfindley@google.com>
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Findley <rfindley@google.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
  • Loading branch information
findleyr committed Feb 19, 2021
1 parent 9a99515 commit 26713b5
Showing 1 changed file with 63 additions and 19 deletions.
82 changes: 63 additions & 19 deletions src/go/types/sanitize.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,54 @@ package types

// sanitizeInfo walks the types contained in info to ensure that all instances
// are expanded.
//
// This includes some objects that may be shared across concurrent
// type-checking passes (such as those in the universe scope), so we are
// careful here not to write types that are already sanitized. This avoids a
// data race as any shared types should already be sanitized.
func sanitizeInfo(info *Info) {
var s sanitizer = make(map[Type]Type)

// Note: Some map entries are not references.
// If modified, they must be assigned back.

for e, tv := range info.Types {
tv.Type = s.typ(tv.Type)
info.Types[e] = tv
if typ := s.typ(tv.Type); typ != tv.Type {
tv.Type = typ
info.Types[e] = tv
}
}

for e, inf := range info.Inferred {
changed := false
for i, targ := range inf.Targs {
inf.Targs[i] = s.typ(targ)
if typ := s.typ(targ); typ != targ {
inf.Targs[i] = typ
changed = true
}
}
if typ := s.typ(inf.Sig); typ != inf.Sig {
inf.Sig = typ.(*Signature)
changed = true
}
if changed {
info.Inferred[e] = inf
}
inf.Sig = s.typ(inf.Sig).(*Signature)
info.Inferred[e] = inf
}

for _, obj := range info.Defs {
if obj != nil {
obj.setType(s.typ(obj.Type()))
if typ := s.typ(obj.Type()); typ != obj.Type() {
obj.setType(typ)
}
}
}

for _, obj := range info.Uses {
if obj != nil {
obj.setType(s.typ(obj.Type()))
if typ := s.typ(obj.Type()); typ != obj.Type() {
obj.setType(typ)
}
}
}

Expand All @@ -57,16 +77,22 @@ func (s sanitizer) typ(typ Type) Type {
// nothing to do

case *Array:
t.elem = s.typ(t.elem)
if elem := s.typ(t.elem); elem != t.elem {
t.elem = elem
}

case *Slice:
t.elem = s.typ(t.elem)
if elem := s.typ(t.elem); elem != t.elem {
t.elem = elem
}

case *Struct:
s.varList(t.fields)

case *Pointer:
t.base = s.typ(t.base)
if base := s.typ(t.base); base != t.base {
t.base = base
}

case *Tuple:
s.tuple(t)
Expand All @@ -87,20 +113,32 @@ func (s sanitizer) typ(typ Type) Type {
s.typ(t.allTypes)

case *Map:
t.key = s.typ(t.key)
t.elem = s.typ(t.elem)
if key := s.typ(t.key); key != t.key {
t.key = key
}
if elem := s.typ(t.elem); elem != t.elem {
t.elem = elem
}

case *Chan:
t.elem = s.typ(t.elem)
if elem := s.typ(t.elem); elem != t.elem {
t.elem = elem
}

case *Named:
t.orig = s.typ(t.orig)
t.underlying = s.typ(t.underlying)
if orig := s.typ(t.orig); orig != t.orig {
t.orig = orig
}
if under := s.typ(t.underlying); under != t.underlying {
t.underlying = under
}
s.typeList(t.targs)
s.funcList(t.methods)

case *TypeParam:
t.bound = s.typ(t.bound)
if bound := s.typ(t.bound); bound != t.bound {
t.bound = bound
}

case *instance:
typ = t.expand()
Expand All @@ -115,7 +153,9 @@ func (s sanitizer) typ(typ Type) Type {

func (s sanitizer) var_(v *Var) {
if v != nil {
v.typ = s.typ(v.typ)
if typ := s.typ(v.typ); typ != v.typ {
v.typ = typ
}
}
}

Expand All @@ -133,7 +173,9 @@ func (s sanitizer) tuple(t *Tuple) {

func (s sanitizer) func_(f *Func) {
if f != nil {
f.typ = s.typ(f.typ)
if typ := s.typ(f.typ); typ != f.typ {
f.typ = typ
}
}
}

Expand All @@ -145,6 +187,8 @@ func (s sanitizer) funcList(list []*Func) {

func (s sanitizer) typeList(list []Type) {
for i, t := range list {
list[i] = s.typ(t)
if typ := s.typ(t); typ != t {
list[i] = typ
}
}
}

0 comments on commit 26713b5

Please sign in to comment.