From 6d8ec893039a39f495c8139012e47754e4518b70 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Mon, 3 Oct 2022 23:46:13 +0700 Subject: [PATCH] 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 Run-TryBot: Cuong Manh Le Auto-Submit: Cuong Manh Le TryBot-Result: Gopher Robot Reviewed-by: Bryan Mills Reviewed-by: Keith Randall --- src/reflect/all_test.go | 18 ++++++++++++++++++ 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. -- 2.48.1