summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2020-06-18 12:51:35 -0700
committerDmitri Shuralyov <dmitshur@golang.org>2020-07-11 02:49:54 +0000
commit3c1722cf30d1edc6756022c7a12efffabcfb098a (patch)
tree8f53e3d1b2337e67e8667b08dcaa36acf241e7be
parent0b75fc7a92b8973601040eed8d13d8775d099f43 (diff)
downloadgo-git-3c1722cf30d1edc6756022c7a12efffabcfb098a.tar.gz
[release-branch.go1.13] reflect: zero stack slots before writing to them with write barriers
reflect.assignTo writes to the target using write barriers. Make sure that the memory it is writing to is zeroed, so the write barrier does not read pointers from uninitialized memory. Fixes #39697 Change-Id: Ia64b2cacc193bffd0c1396bbce1dfb8182d4905b Reviewed-on: https://go-review.googlesource.com/c/go/+/238760 Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org> (cherry picked from commit 3dec253783e1211989102ac6abd34cddbf8ba0e6) Reviewed-on: https://go-review.googlesource.com/c/go/+/238862 Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
-rw-r--r--src/reflect/value.go8
-rw-r--r--src/runtime/stack.go1
-rw-r--r--test/fixedbugs/issue39541.go33
3 files changed, 42 insertions, 0 deletions
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 9ea95bc1d9..6daeb65b0f 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -577,6 +577,13 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer, retValid *bool) {
// Convert v to type typ if v is assignable to a variable
// of type t in the language spec.
// See issue 28761.
+ if typ.Kind() == Interface {
+ // We must clear the destination before calling assignTo,
+ // in case assignTo writes (with memory barriers) to the
+ // target location used as scratch space. See issue 39541.
+ *(*uintptr)(addr) = 0
+ *(*uintptr)(add(addr, ptrSize, "typ.size == 2*ptrSize")) = 0
+ }
v = v.assignTo("reflect.MakeFunc", typ, addr)
// We are writing to stack. No write barrier.
@@ -2367,6 +2374,7 @@ func NewAt(typ Type, p unsafe.Pointer) Value {
// assignTo returns a value v that can be assigned directly to typ.
// It panics if v is not assignable to typ.
// For a conversion to an interface type, target is a suggested scratch space to use.
+// target must be initialized memory (or nil).
func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value {
if v.flag&flagMethod != 0 {
v = makeMethodValue(context, v)
diff --git a/src/runtime/stack.go b/src/runtime/stack.go
index 7ae3eeef83..39876e2cc7 100644
--- a/src/runtime/stack.go
+++ b/src/runtime/stack.go
@@ -543,6 +543,7 @@ func adjustpointer(adjinfo *adjustinfo, vpp unsafe.Pointer) {
}
// Information from the compiler about the layout of stack frames.
+// Note: this type must agree with reflect.bitVector.
type bitvector struct {
n int32 // # of bits
bytedata *uint8
diff --git a/test/fixedbugs/issue39541.go b/test/fixedbugs/issue39541.go
new file mode 100644
index 0000000000..fba52916eb
--- /dev/null
+++ b/test/fixedbugs/issue39541.go
@@ -0,0 +1,33 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "reflect"
+
+func sub(args []reflect.Value) []reflect.Value {
+ type A struct {
+ s int
+ t int
+ }
+ return []reflect.Value{reflect.ValueOf(A{1, 2})}
+}
+
+func main() {
+ f := reflect.MakeFunc(reflect.TypeOf((func() interface{})(nil)), sub).Interface().(func() interface{})
+ c := make(chan bool, 100)
+ for i := 0; i < 100; i++ {
+ go func() {
+ for j := 0; j < 10000; j++ {
+ f()
+ }
+ c <- true
+ }()
+ }
+ for i := 0; i < 100; i++ {
+ <-c
+ }
+}