Skip to content

Commit 3e7f550

Browse files
cherrymuinebulabox
authored andcommitted
reflect: eliminate write barrier for copying result in callReflect
We are copying the results to uninitialized stack space. Write barrier is not needed. Fixes golang#30041. Change-Id: Ia91d74dbafd96dc2bd92de0cb479808991dda03e Reviewed-on: https://go-review.googlesource.com/c/160737 Run-TryBot: Cherry Zhang <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent 06a8138 commit 3e7f550

File tree

2 files changed

+66
-2
lines changed

2 files changed

+66
-2
lines changed

src/reflect/value.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -561,10 +561,11 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer, retValid *bool) {
561561
continue
562562
}
563563
addr := add(ptr, off, "typ.size > 0")
564+
// We are writing to stack. No write barrier.
564565
if v.flag&flagIndir != 0 {
565-
typedmemmove(typ, addr, v.ptr)
566+
memmove(addr, v.ptr, typ.size)
566567
} else {
567-
*(*unsafe.Pointer)(addr) = v.ptr
568+
*(*uintptr)(addr) = uintptr(v.ptr)
568569
}
569570
off += typ.size
570571
}

test/fixedbugs/issue30041.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// run
2+
3+
// Copyright 2019 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+
// Issue 30041: copying results of a reflect-generated
8+
// call on stack should not have write barrier.
9+
10+
package main
11+
12+
import (
13+
"reflect"
14+
"runtime"
15+
"unsafe"
16+
)
17+
18+
var badPtr uintptr
19+
20+
var sink []byte
21+
22+
func init() {
23+
// Allocate large enough to use largeAlloc.
24+
b := make([]byte, 1<<16-1)
25+
sink = b // force heap allocation
26+
// Any space between the object and the end of page is invalid to point to.
27+
badPtr = uintptr(unsafe.Pointer(&b[len(b)-1])) + 1
28+
}
29+
30+
type ft func() *int
31+
32+
var fn ft
33+
34+
func rf([]reflect.Value) []reflect.Value {
35+
a := reflect.ValueOf((*int)(nil))
36+
return []reflect.Value{a}
37+
}
38+
39+
const N = 1000
40+
41+
func main() {
42+
fn = reflect.MakeFunc(reflect.TypeOf(fn), rf).Interface().(ft)
43+
44+
// Keep running GC so the write barrier is on.
45+
go func() {
46+
for i := 0; i < N; i++ {
47+
runtime.GC()
48+
}
49+
}()
50+
51+
var x [10]uintptr
52+
for i := range x {
53+
x[i] = badPtr
54+
}
55+
for i := 0; i < N; i++ {
56+
runtime.Gosched()
57+
use(x) // prepare bad pointers on stack
58+
fn()
59+
}
60+
}
61+
62+
//go:noinline
63+
func use([10]uintptr) {}

0 commit comments

Comments
 (0)