Skip to content

Commit 3dec253

Browse files
committed
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 #39541 Change-Id: Ia64b2cacc193bffd0c1396bbce1dfb8182d4905b Reviewed-on: https://go-review.googlesource.com/c/go/+/238760 Run-TryBot: Keith Randall <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent a07e281 commit 3dec253

4 files changed

Lines changed: 43 additions & 0 deletions

File tree

src/reflect/type.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3068,6 +3068,7 @@ func ifaceIndir(t *rtype) bool {
30683068
return t.kind&kindDirectIface == 0
30693069
}
30703070

3071+
// Note: this type must agree with runtime.bitvector.
30713072
type bitVector struct {
30723073
n uint32 // number of bits
30733074
data []byte

src/reflect/value.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,13 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer, retValid *bool) {
589589
// Convert v to type typ if v is assignable to a variable
590590
// of type t in the language spec.
591591
// See issue 28761.
592+
if typ.Kind() == Interface {
593+
// We must clear the destination before calling assignTo,
594+
// in case assignTo writes (with memory barriers) to the
595+
// target location used as scratch space. See issue 39541.
596+
*(*uintptr)(addr) = 0
597+
*(*uintptr)(add(addr, ptrSize, "typ.size == 2*ptrSize")) = 0
598+
}
592599
v = v.assignTo("reflect.MakeFunc", typ, addr)
593600

594601
// We are writing to stack. No write barrier.
@@ -2381,6 +2388,7 @@ func NewAt(typ Type, p unsafe.Pointer) Value {
23812388
// assignTo returns a value v that can be assigned directly to typ.
23822389
// It panics if v is not assignable to typ.
23832390
// For a conversion to an interface type, target is a suggested scratch space to use.
2391+
// target must be initialized memory (or nil).
23842392
func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value {
23852393
if v.flag&flagMethod != 0 {
23862394
v = makeMethodValue(context, v)

src/runtime/stack.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,7 @@ func adjustpointer(adjinfo *adjustinfo, vpp unsafe.Pointer) {
556556
}
557557

558558
// Information from the compiler about the layout of stack frames.
559+
// Note: this type must agree with reflect.bitVector.
559560
type bitvector struct {
560561
n int32 // # of bits
561562
bytedata *uint8

test/fixedbugs/issue39541.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// run
2+
3+
// Copyright 2020 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package main
8+
9+
import "reflect"
10+
11+
func sub(args []reflect.Value) []reflect.Value {
12+
type A struct {
13+
s int
14+
t int
15+
}
16+
return []reflect.Value{reflect.ValueOf(A{1, 2})}
17+
}
18+
19+
func main() {
20+
f := reflect.MakeFunc(reflect.TypeOf((func() interface{})(nil)), sub).Interface().(func() interface{})
21+
c := make(chan bool, 100)
22+
for i := 0; i < 100; i++ {
23+
go func() {
24+
for j := 0; j < 10000; j++ {
25+
f()
26+
}
27+
c <- true
28+
}()
29+
}
30+
for i := 0; i < 100; i++ {
31+
<-c
32+
}
33+
}

0 commit comments

Comments
 (0)