1// run 2 3// Copyright 2014 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// The liveness code used to say that, in func g, s was live 8// starting at its declaration, because it appears to have its 9// address taken by the closure (different s, but the parser 10// gets slightly confused, a separate bug). The liveness analysis 11// saw s as having its address taken but the register optimizer 12// did not. This mismatch meant that s would be marked live 13// (and therefore initialized) at the call to f, but the register optimizer 14// would optimize away the initialization of s before f, causing the 15// garbage collector to use unused data. 16// The register optimizer has been changed to respect the 17// same "address taken" flag that the liveness analysis uses, 18// even if it cannot see any address being taken in the actual 19// machine code. This is conservative but keeps the two consistent, 20// which is the most important thing. 21 22package main 23 24import "runtime" 25 26//go:noinline 27func f() interface{} { 28 runtime.GC() 29 return nil 30} 31 32//go:noinline 33func g() { 34 var s interface{} 35 _ = func() { 36 s := f() 37 _ = s 38 } 39 s = f() 40 useiface(s) 41 useiface(s) 42} 43 44//go:noinline 45func useiface(x interface{}) { 46} 47 48//go:noinline 49func h() { 50 var x [16]uintptr 51 for i := range x { 52 x[i] = 1 53 } 54 55 useint(x[0]) 56 useint(x[1]) 57 useint(x[2]) 58 useint(x[3]) 59} 60 61//go:noinline 62func useint(x uintptr) { 63} 64 65func main() { 66 // scribble non-zero values on stack 67 h() 68 // call function that used to let the garbage collector 69 // see uninitialized stack values; it will see the 70 // nonzero values. 71 g() 72} 73 74func big(x int) { 75 if x >= 0 { 76 big(x - 1) 77 } 78} 79