aboutsummaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authorCuong Manh Le <cuong.manhle.vn@gmail.com>2022-10-03 23:46:13 +0700
committerGopher Robot <gobot@golang.org>2022-10-03 20:06:58 +0000
commit6d8ec893039a39f495c8139012e47754e4518b70 (patch)
treea9c17f9e8360d97fef7df2dfb91d78defff6d2ce /src/reflect
parent12daabb9156adb73fda453cae939ab4e3cb8e52f (diff)
downloadgo-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.go18
-rw-r--r--src/reflect/type.go28
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.