mirror of
https://github.com/golang/go
synced 2024-11-26 17:26:56 -07:00
f23c601bf9
It is possible that a "volatile" value (one that can be clobbered by preparing args of a call) to be used in multiple write barrier calls. We used to copy the volatile value right before each call. But this doesn't work if the value is used the second time, after the first call where it is already clobbered. Copy it before emitting any call. Fixes #30977. Change-Id: Iedcc91ad848d5ded547bf37a8359c125d32e994c Reviewed-on: https://go-review.googlesource.com/c/go/+/168677 Run-TryBot: Cherry Zhang <cherryyz@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
53 lines
865 B
Go
53 lines
865 B
Go
// run
|
|
|
|
// Copyright 2019 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.
|
|
|
|
// Issue 30977: write barrier call clobbers volatile
|
|
// value when there are multiple uses of the value.
|
|
|
|
package main
|
|
|
|
import "runtime"
|
|
|
|
type T struct {
|
|
a, b, c, d, e string
|
|
}
|
|
|
|
//go:noinline
|
|
func g() T {
|
|
return T{"a", "b", "c", "d", "e"}
|
|
}
|
|
|
|
//go:noinline
|
|
func f() {
|
|
// The compiler optimizes this to direct copying
|
|
// the call result to both globals, with write
|
|
// barriers. The first write barrier call clobbers
|
|
// the result of g on stack.
|
|
X = g()
|
|
Y = X
|
|
}
|
|
|
|
var X, Y T
|
|
|
|
const N = 1000
|
|
|
|
func main() {
|
|
// Keep GC running so the write barrier is on.
|
|
go func() {
|
|
for {
|
|
runtime.GC()
|
|
}
|
|
}()
|
|
|
|
for i := 0; i < N; i++ {
|
|
runtime.Gosched()
|
|
f()
|
|
if X != Y {
|
|
panic("FAIL")
|
|
}
|
|
}
|
|
}
|