]> Cypherpunks.ru repositories - gostls13.git/commitdiff
reflect: fix race condition on funcTypes
authorCuong Manh Le <cuong.manhle.vn@gmail.com>
Mon, 3 Oct 2022 16:46:13 +0000 (23:46 +0700)
committerGopher Robot <gobot@golang.org>
Mon, 3 Oct 2022 20:06:58 +0000 (20:06 +0000)
CL 425314 made creating funcTypes using StructOf, and using a mutex to
protect read+write to funcTypes. However, after initializing funcTypes,
it is accessed in FuncOf without holding lock, causing a race.

Fixing it by returning the n-th Type directly from initFuncTypes, so the
accessing funcTypes will always be guarded by a mutex.

Fixes #56011

Change-Id: I1b50d1ae342943f16f368b8606f2614076dc90fb
Reviewed-on: https://go-review.googlesource.com/c/go/+/437997
Reviewed-by: Keith Randall <khr@google.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
src/reflect/all_test.go
src/reflect/type.go

index d80e6e5d863db077a55a552159cabca31be4d493..5b43669384cffe0d63e211376c3cb2a3b6da6e97 100644 (file)
@@ -15,6 +15,7 @@ import (
        "io"
        "math"
        "math/rand"
+       "net"
        "os"
        . "reflect"
        "reflect/internal/example1"
@@ -8240,3 +8241,20 @@ func TestValue_Equal(t *testing.T) {
                }
        }
 }
+
+func TestInitFuncTypes(t *testing.T) {
+       n := 100
+       var wg sync.WaitGroup
+
+       wg.Add(n)
+       for i := 0; i < n; i++ {
+               go func() {
+                       defer wg.Done()
+                       ipT := TypeOf(net.IP{})
+                       for i := 0; i < ipT.NumMethod(); i++ {
+                               _ = ipT.Method(i)
+                       }
+               }()
+       }
+       wg.Wait()
+}
index 13fa725a22ebbba08d0906bca3cbae3aeaf36f22..339c982087afa060173080ee5b1b1f27b2f9e81e 100644 (file)
@@ -2002,19 +2002,16 @@ func MapOf(key, elem Type) Type {
 var funcTypes []Type
 var funcTypesMutex sync.Mutex
 
-func initFuncTypes(n int) {
+func initFuncTypes(n int) Type {
        funcTypesMutex.Lock()
        defer funcTypesMutex.Unlock()
-       if n < len(funcTypes) {
-               if funcTypes[n] != nil {
-                       return
-               }
-       } else {
-               newFuncTypes := make([]Type, n+1)
-               copy(newFuncTypes, funcTypes)
-               funcTypes = newFuncTypes
+       if n < len(funcTypes) && funcTypes[n] != nil {
+               return funcTypes[n]
        }
 
+       newFuncTypes := make([]Type, n+1)
+       copy(newFuncTypes, funcTypes)
+       funcTypes = newFuncTypes
        funcTypes[n] = StructOf([]StructField{
                {
                        Name: "FuncType",
@@ -2025,6 +2022,7 @@ func initFuncTypes(n int) {
                        Type: ArrayOf(n, TypeOf(&rtype{})),
                },
        })
+       return funcTypes[n]
 }
 
 // FuncOf returns the function type with the given argument and result types.
@@ -2044,17 +2042,13 @@ func FuncOf(in, out []Type, variadic bool) Type {
        prototype := *(**funcType)(unsafe.Pointer(&ifunc))
        n := len(in) + len(out)
 
-       var ft *funcType
-       var args []*rtype
-       if n <= 128 {
-               initFuncTypes(n)
-               o := New(funcTypes[n]).Elem()
-               ft = (*funcType)(unsafe.Pointer(o.Field(0).Addr().Pointer()))
-               args = unsafe.Slice((**rtype)(unsafe.Pointer(o.Field(1).Addr().Pointer())), n)[0:0:n]
-       } else {
+       if n > 128 {
                panic("reflect.FuncOf: too many arguments")
        }
 
+       o := New(initFuncTypes(n)).Elem()
+       ft := (*funcType)(unsafe.Pointer(o.Field(0).Addr().Pointer()))
+       args := unsafe.Slice((**rtype)(unsafe.Pointer(o.Field(1).Addr().Pointer())), n)[0:0:n]
        *ft = *prototype
 
        // Build a hash and minimally populate ft.