]> Cypherpunks repositories - gostls13.git/commit
go/types, types2: set t.underlying exactly once in resolveUnderlying
authorMark Freeman <mark@golang.org>
Thu, 23 Oct 2025 16:52:19 +0000 (12:52 -0400)
committerGopher Robot <gobot@golang.org>
Thu, 23 Oct 2025 20:01:36 +0000 (13:01 -0700)
commitcf826bfcb494a7dba5451bd7e4432f150590b19e
treeef5d9f6c19cb8deec4cf7a7e1e9cce8b72674821
parentc4e910895b3d91e4c7d4d6b5cd0af5e0eb787b72
go/types, types2: set t.underlying exactly once in resolveUnderlying

While the locking in Named.resolveUnderlying is mostly fine, we do not
perform an atomic read before the write to underlying.

If resolveUnderlying returns and another thread was waiting on the lock,
it can perform a second (in this case identical) write to t.underlying.
A reader thread on n.underlying can thus observe either of those writes,
tripping the race detector.

Michael was kind enough to provide a diagram:

   T1                                   T2
1. t.stateHas(underlying) // false
2.                                      t.stateHas(underlying) // false
3. t.mu.Lock() // acquired
4.                                      t.mu.Lock() // blocked
5. t.underlying = u
6. t.setState(underlying)
7. t.mu.Unlock()
8.                                      t.underlying = u // overwritten
9.                                      t.setState(underlying)
10.                                     t.mu.Unlock()

Adding a second check before setting t.underlying prevents the write on
line 8.

Change-Id: Ia43a6d3ba751caef436b9926c6ece2a71dfb9d38
Reviewed-on: https://go-review.googlesource.com/c/go/+/714300
Auto-Submit: Mark Freeman <markfreeman@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
src/cmd/compile/internal/types2/named.go
src/go/types/named.go