| // 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() |
| } |