Source file test/fixedbugs/issue79186.go

     1  // run
     2  
     3  // Copyright 2026 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  // Issue 79186: on ppc64le (POWER8/9), atomic add operations lacked a
     8  // post-barrier (acquire ordering), allowing loads after an RWMutex.RLock
     9  // to be speculatively reordered before the lock acquisition, causing
    10  // concurrent map read and map write.
    11  
    12  package main
    13  
    14  import (
    15  	"runtime"
    16  	"sync"
    17  )
    18  
    19  type M struct {
    20  	mu sync.RWMutex
    21  	m  map[int]int
    22  }
    23  
    24  func NewM() *M {
    25  	return &M{m: make(map[int]int)}
    26  }
    27  
    28  func (x *M) Get(k int) (int, bool) {
    29  	x.mu.RLock()
    30  	v, ok := x.m[k]
    31  	x.mu.RUnlock()
    32  	return v, ok
    33  }
    34  
    35  func (x *M) Set(k, v int) {
    36  	x.mu.Lock()
    37  	x.m[k] = v
    38  	x.mu.Unlock()
    39  }
    40  
    41  func main() {
    42  	runtime.GOMAXPROCS(2)
    43  
    44  	x := NewM()
    45  
    46  	const goroutines = 256
    47  	const iters = 200000
    48  
    49  	var wg sync.WaitGroup
    50  	wg.Add(goroutines)
    51  
    52  	for g := 0; g < goroutines; g++ {
    53  		go func(id int) {
    54  			defer wg.Done()
    55  			for i := 0; i < iters; i++ {
    56  				k := (id + i) & 15
    57  				if _, ok := x.Get(k); !ok {
    58  					x.Set(k, i)
    59  				} else if i&7 == 0 {
    60  					x.Set(k, i)
    61  				}
    62  			}
    63  		}(g)
    64  	}
    65  
    66  	wg.Wait()
    67  }
    68  

View as plain text