Go version
go version go1.27-devel_3b5954c634 linux/ppc64le
Output of go env in your module/workspace:
AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOARCH='ppc64le'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/home/user/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/user/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build438762286=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='ppc64le'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/dev/null'
GOMODCACHE='/home/user/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/user/go'
GOPPC64='power8'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/user/golang/godevel'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/user/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/user/golang/godevel/pkg/tool/linux_ppc64le'
GOVCS=''
GOVERSION='go1.27-devel_5bb6d165f0 Tue Apr 28 18:11:27 2026 -0700'
GOWORK=''
PKG_CONFIG='pkg-config'
What did you do?
I ran the following commands to run the test and reproduce the issue across multiple runs:
export GOMAXPROCS=2
go test -v -count=50 -run TestRWMutexMap
Here is the standalone reproducer used in rwmutex_map_test.go:
package repro
import (
"sync"
"testing"
)
type M struct {
mu sync.RWMutex
m map[int]int
}
func NewM() *M {
return &M{m: make(map[int]int)}
}
func (x *M) Get(k int) (int, bool) {
x.mu.RLock()
v, ok := x.m[k]
x.mu.RUnlock()
return v, ok
}
func (x *M) Set(k, v int) {
x.mu.Lock()
x.m[k] = v
x.mu.Unlock()
}
func TestRWMutexMap(t *testing.T) {
x := NewM()
const goroutines = 256
const iters = 200000
var wg sync.WaitGroup
wg.Add(goroutines)
for g := 0; g < goroutines; g++ {
go func(id int) {
defer wg.Done()
for i := 0; i < iters; i++ {
k := (id + i) & 15
if _, ok := x.Get(k); !ok {
x.Set(k, i)
} else if i&7 == 0 {
x.Set(k, i)
}
}
}(g)
}
wg.Wait()
}
What did you see happen?
Intermittent failures trigger the following fatal error:
fatal error: concurrent map read and map write
internal/runtime/maps.fatal
repro.(*M).Get
rwmutex_map_test.go:19
What did you expect to see?
The test should pass. sync.RWMutex should properly prevent concurrent map read/write conditions.
Additional context
Replacing sync.RWMutex with sync.Mutex eliminates the failure in my runs under the same workload.
// ...
type M struct {
mu sync.Mutex
m map[int]int
}
func (x *M) Get(k int) (int, bool) {
x.mu.Lock()
v, ok := x.m[k]
x.mu.Unlock()
return v, ok
}
// ...
Results: The test passes consistently. No failures were observed under the same workload.
Environment Observations:
Reproduced on POWER8 and POWER9 (ppc64le).
Not reproduced on POWER10 (ppc64le).
Additional Notes:
The issue only reproduces when GOMAXPROCS > 1.
It does not reproduce with GOMAXPROCS = 1.
It does not reproduce under -race (likely due to additional synchronization and timing changes).
This issue was initially observed in real workloads (Kubernetes expiring cache tests) where replacing RWMutex with Mutex eliminated test flakes.
Go version
go version go1.27-devel_3b5954c634 linux/ppc64le
Output of
go envin your module/workspace:What did you do?
I ran the following commands to run the test and reproduce the issue across multiple runs:
Here is the standalone reproducer used in rwmutex_map_test.go:
What did you see happen?
Intermittent failures trigger the following fatal error:
What did you expect to see?
The test should pass. sync.RWMutex should properly prevent concurrent map read/write conditions.
Additional context
Replacing
sync.RWMutexwithsync.Mutexeliminates the failure in my runs under the same workload.Results: The test passes consistently. No failures were observed under the same workload.
Environment Observations:
Reproduced on POWER8 and POWER9 (ppc64le).
Not reproduced on POWER10 (ppc64le).
Additional Notes:
The issue only reproduces when GOMAXPROCS > 1.
It does not reproduce with GOMAXPROCS = 1.
It does not reproduce under -race (likely due to additional synchronization and timing changes).
This issue was initially observed in real workloads (Kubernetes expiring cache tests) where replacing RWMutex with Mutex eliminated test flakes.