redis / go-redis

Redis Go client
https://redis.uptrace.dev
BSD 2-Clause "Simplified" License
19.95k stars 2.36k forks source link

fix: race slice for list function of ring client #2931

Open rfyiamcool opened 7 months ago

rfyiamcool commented 7 months ago

summary

s1 := s0 is shallow copy. when concurrently process read and write (append) operator for slice, raise data race. so, use copy() to deep copy slice object.

image

test

ut

func TestRaceSlice(t *testing.T) {
    var a1 = make([]string, 3)
    var b1 = []string{"a", "b", "c"}

    // race error
    a1 = b1

    // race ok
    // copy(a1, b1)

    fmt.Printf("a1 >%v", (*reflect.SliceHeader)(unsafe.Pointer(&a1)))
    fmt.Println()
    fmt.Printf("b1 >%v", (*reflect.SliceHeader)(unsafe.Pointer(&b1)))

    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        defer wg.Done()
        for i := 0; i < 10000; i++ {
            a1[0] = "aa"
        }
    }()

    wg.Add(1)
    go func() {
        defer wg.Done()
        for i := 0; i < 10000; i++ {
            b1[0] = "bb"
        }
    }()

    wg.Wait()
}

test result

=== RUN   TestRaceSlice
a1 >&{824636064176 3 3}
b1 >&{824636064176 3 3}==================
WARNING: DATA RACE
Write at 0x00c00023c1b0 by goroutine 8:
  github.com/redis/go-redis/v9_test.TestRaceSlice.func1()
      /Users/ruifengyun/github/rfyiamcool/go-redis/main_test.go:504 +0xcf

Previous write at 0x00c00023c1b0 by goroutine 9:
  github.com/redis/go-redis/v9_test.TestRaceSlice.func2()
      /Users/ruifengyun/github/rfyiamcool/go-redis/main_test.go:512 +0xcf

Goroutine 8 (running) created at:
  github.com/redis/go-redis/v9_test.TestRaceSlice()
      /Users/ruifengyun/github/rfyiamcool/go-redis/main_test.go:501 +0x427
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1595 +0x238
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1648 +0x44

Goroutine 9 (running) created at:
  github.com/redis/go-redis/v9_test.TestRaceSlice()
      /Users/ruifengyun/github/rfyiamcool/go-redis/main_test.go:509 +0x4e4
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1595 +0x238
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1648 +0x44
==================
    testing.go:1465: race detected during execution of test
--- FAIL: TestRaceSlice (0.00s)
=== NAME  
    testing.go:1465: race detected during execution of test
FAIL
FAIL    github.com/redis/go-redis/v9    0.384s
FAIL