| // Copyright 2016 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 gc |
| |
| import "testing" |
| |
| type T struct { |
| x [2]int64 // field that will be clobbered. Also makes type not SSAable. |
| p *byte // has a pointer |
| } |
| |
| //go:noinline |
| func makeT() T { |
| return T{} |
| } |
| |
| var g T |
| |
| var sink interface{} |
| |
| func TestIssue15854(t *testing.T) { |
| for i := 0; i < 10000; i++ { |
| if g.x[0] != 0 { |
| t.Fatalf("g.x[0] clobbered with %x\n", g.x[0]) |
| } |
| // The bug was in the following assignment. The return |
| // value of makeT() is not copied out of the args area of |
| // stack frame in a timely fashion. So when write barriers |
| // are enabled, the marshaling of the args for the write |
| // barrier call clobbers the result of makeT() before it is |
| // read by the write barrier code. |
| g = makeT() |
| sink = make([]byte, 1000) // force write barriers to eventually happen |
| } |
| } |
| func TestIssue15854b(t *testing.T) { |
| const N = 10000 |
| a := make([]T, N) |
| for i := 0; i < N; i++ { |
| a = append(a, makeT()) |
| sink = make([]byte, 1000) // force write barriers to eventually happen |
| } |
| for i, v := range a { |
| if v.x[0] != 0 { |
| t.Fatalf("a[%d].x[0] clobbered with %x\n", i, v.x[0]) |
| } |
| } |
| } |