]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.14] reflect: zero stack slots before writing to them with write...
authorKeith Randall <khr@golang.org>
Thu, 18 Jun 2020 19:51:35 +0000 (12:51 -0700)
committerDmitri Shuralyov <dmitshur@golang.org>
Sat, 11 Jul 2020 02:49:14 +0000 (02:49 +0000)
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 #39698

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/+/238861

src/reflect/type.go
src/reflect/value.go
src/runtime/stack.go
test/fixedbugs/issue39541.go [new file with mode: 0644]

index cd8522d9045c1bd194a0762cb6388c019778fe47..8a37a1245c40faf8e1532c5e99693eb6aa8e8994 100644 (file)
@@ -3067,6 +3067,7 @@ func ifaceIndir(t *rtype) bool {
        return t.kind&kindDirectIface == 0
 }
 
+// Note: this type must agree with runtime.bitvector.
 type bitVector struct {
        n    uint32 // number of bits
        data []byte
index 2b7dd66a8c1a90a23ccd931a63a29d06219173f1..45517bef40703e56499b5eeee5449ffec926e06c 100644 (file)
@@ -574,6 +574,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)
index ebbe3e013de5eb524307a44813b538b7ce0bfddb..0f5b16543d61153224885164de0bc6211bf64554 100644 (file)
@@ -551,6 +551,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 (file)
index 0000000..fba5291
--- /dev/null
@@ -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
+       }
+}