modernc.org/gc@v1.0.1-0.20240304020402-f0dba7c97c2b/testdata/errchk/test/fixedbugs/bug484.go (about) 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 22 package main 23 24 import "runtime" 25 26 //go:noinline 27 func f() interface{} { 28 runtime.GC() 29 return nil 30 } 31 32 //go:noinline 33 func 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 45 func useiface(x interface{}) { 46 } 47 48 //go:noinline 49 func 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 62 func useint(x uintptr) { 63 } 64 65 func 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 74 func big(x int) { 75 if x >= 0 { 76 big(x - 1) 77 } 78 }