diff options
| author | Cuong Manh Le <cuong.manhle.vn@gmail.com> | 2022-10-03 23:46:13 +0700 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2022-10-03 20:06:58 +0000 |
| commit | 6d8ec893039a39f495c8139012e47754e4518b70 (patch) | |
| tree | a9c17f9e8360d97fef7df2dfb91d78defff6d2ce /src/reflect | |
| parent | 12daabb9156adb73fda453cae939ab4e3cb8e52f (diff) | |
| download | go-6d8ec893039a39f495c8139012e47754e4518b70.tar.xz | |
reflect: fix race condition on funcTypes
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>
Diffstat (limited to 'src/reflect')
| -rw-r--r-- | src/reflect/all_test.go | 18 | ||||
| -rw-r--r-- | src/reflect/type.go | 28 |
2 files changed, 29 insertions, 17 deletions
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index d80e6e5d86..5b43669384 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -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() +} diff --git a/src/reflect/type.go b/src/reflect/type.go index 13fa725a22..339c982087 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -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. |
