| // run |
| |
| // Copyright 2014 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. |
| |
| // The liveness code used to say that, in func g, s was live |
| // starting at its declaration, because it appears to have its |
| // address taken by the closure (different s, but the parser |
| // gets slightly confused, a separate bug). The liveness analysis |
| // saw s as having its address taken but the register optimizer |
| // did not. This mismatch meant that s would be marked live |
| // (and therefore initialized) at the call to f, but the register optimizer |
| // would optimize away the initialization of s before f, causing the |
| // garbage collector to use unused data. |
| // The register optimizer has been changed to respect the |
| // same "address taken" flag that the liveness analysis uses, |
| // even if it cannot see any address being taken in the actual |
| // machine code. This is conservative but keeps the two consistent, |
| // which is the most important thing. |
| |
| package main |
| |
| import "runtime" |
| |
| //go:noinline |
| func f() interface{} { |
| runtime.GC() |
| return nil |
| } |
| |
| //go:noinline |
| func g() { |
| var s interface{} |
| _ = func() { |
| s := f() |
| _ = s |
| } |
| s = f() |
| useiface(s) |
| useiface(s) |
| } |
| |
| //go:noinline |
| func useiface(x interface{}) { |
| } |
| |
| //go:noinline |
| func h() { |
| var x [16]uintptr |
| for i := range x { |
| x[i] = 1 |
| } |
| |
| useint(x[0]) |
| useint(x[1]) |
| useint(x[2]) |
| useint(x[3]) |
| } |
| |
| //go:noinline |
| func useint(x uintptr) { |
| } |
| |
| func main() { |
| // scribble non-zero values on stack |
| h() |
| // call function that used to let the garbage collector |
| // see uninitialized stack values; it will see the |
| // nonzero values. |
| g() |
| } |
| |
| func big(x int) { |
| if x >= 0 { |
| big(x - 1) |
| } |
| } |