From 2d755a818c8802cf8fb9f2516ae20c9da3b84fdb Mon Sep 17 00:00:00 2001 From: Weizhen Wang Date: Mon, 9 Jan 2023 11:20:22 +0800 Subject: [PATCH] executor: fix data race at the ShowExec (#39817) close pingcap/tidb#39816, close pingcap/tidb#40295 --- executor/BUILD.bazel | 1 + executor/show.go | 8 +++++--- util/slice/slice.go | 13 +++++++++++++ util/slice/slice_test.go | 16 ++++++++++++++++ 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/executor/BUILD.bazel b/executor/BUILD.bazel index a3fa2dfc8b7a9..35703034b1214 100644 --- a/executor/BUILD.bazel +++ b/executor/BUILD.bazel @@ -192,6 +192,7 @@ go_library( "//util/servermemorylimit", "//util/set", "//util/size", + "//util/slice", "//util/sqlexec", "//util/stmtsummary", "//util/stringutil", diff --git a/executor/show.go b/executor/show.go index d394ed356cd1c..99e9d80121a01 100644 --- a/executor/show.go +++ b/executor/show.go @@ -69,6 +69,7 @@ import ( "github.com/pingcap/tidb/util/memory" "github.com/pingcap/tidb/util/sem" "github.com/pingcap/tidb/util/set" + "github.com/pingcap/tidb/util/slice" "github.com/pingcap/tidb/util/sqlexec" "github.com/pingcap/tidb/util/stringutil" "golang.org/x/exp/slices" @@ -306,13 +307,14 @@ func (v *visibleChecker) Leave(in ast.Node) (out ast.Node, ok bool) { } func (e *ShowExec) fetchShowBind() error { - var bindRecords []*bindinfo.BindRecord + var tmp []*bindinfo.BindRecord if !e.GlobalScope { handle := e.ctx.Value(bindinfo.SessionBindInfoKeyType).(*bindinfo.SessionHandle) - bindRecords = handle.GetAllBindRecord() + tmp = handle.GetAllBindRecord() } else { - bindRecords = domain.GetDomain(e.ctx).BindHandle().GetAllBindRecord() + tmp = domain.GetDomain(e.ctx).BindHandle().GetAllBindRecord() } + bindRecords := slice.Copy(tmp) // Remove the invalid bindRecord. ind := 0 for _, bindData := range bindRecords { diff --git a/util/slice/slice.go b/util/slice/slice.go index 078772d58c15a..12738614a115f 100644 --- a/util/slice/slice.go +++ b/util/slice/slice.go @@ -39,3 +39,16 @@ func AllOf(s interface{}, p func(int) bool) bool { } return NoneOf(s, np) } + +// Copy is a deep copy of the slice. +func Copy[T any](a []*T) []*T { + b := make([]*T, len(a)) + for i, p := range a { + if p == nil { + continue + } + v := *p + b[i] = &v + } + return b +} diff --git a/util/slice/slice_test.go b/util/slice/slice_test.go index 5a9b9ec17100f..787e0584c0f77 100644 --- a/util/slice/slice_test.go +++ b/util/slice/slice_test.go @@ -43,3 +43,19 @@ func TestSlice(t *testing.T) { }) } } + +func TestCopy(t *testing.T) { + type T int + v0, v1, v2, v3 := T(0), T(1), T(2), T(3) + s := []*T{&v0, &v1, &v2, &v3, nil} + e := Copy(s) + require.Equal(t, len(s), len(e)) + for i := range s { + if s[i] == nil { + require.Nil(t, e[i]) + } else { + require.Equal(t, *s[i], *e[i]) + require.True(t, s[i] != e[i]) + } + } +}