// run // Copyright 2026 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Issue 79186: on ppc64le (POWER8/9), atomic add operations lacked a // post-barrier (acquire ordering), allowing loads after an RWMutex.RLock // to be speculatively reordered before the lock acquisition, causing // concurrent map read and map write. package main import ( "runtime" "sync" ) 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 main() { runtime.GOMAXPROCS(2) 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() }