Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 1 | // run |
| 2 | |
Dan Willemsen | 38f2dba | 2016-07-08 14:54:35 -0700 | [diff] [blame] | 3 | // Copyright 2014 The Go Authors. All rights reserved. |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 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 | |
Dan Willemsen | 38f2dba | 2016-07-08 14:54:35 -0700 | [diff] [blame] | 26 | //go:noinline |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 27 | func f() interface{} { |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 28 | runtime.GC() |
| 29 | return nil |
| 30 | } |
| 31 | |
Dan Willemsen | 38f2dba | 2016-07-08 14:54:35 -0700 | [diff] [blame] | 32 | //go:noinline |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 33 | func g() { |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 34 | var s interface{} |
| 35 | _ = func() { |
| 36 | s := f() |
| 37 | _ = s |
| 38 | } |
| 39 | s = f() |
| 40 | useiface(s) |
| 41 | useiface(s) |
| 42 | } |
| 43 | |
Dan Willemsen | 38f2dba | 2016-07-08 14:54:35 -0700 | [diff] [blame] | 44 | //go:noinline |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 45 | func useiface(x interface{}) { |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 46 | } |
| 47 | |
Dan Willemsen | 38f2dba | 2016-07-08 14:54:35 -0700 | [diff] [blame] | 48 | //go:noinline |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 49 | func h() { |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 50 | var x [16]uintptr |
| 51 | for i := range x { |
| 52 | x[i] = 1 |
| 53 | } |
Dan Willemsen | 38f2dba | 2016-07-08 14:54:35 -0700 | [diff] [blame] | 54 | |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 55 | useint(x[0]) |
| 56 | useint(x[1]) |
| 57 | useint(x[2]) |
| 58 | useint(x[3]) |
| 59 | } |
| 60 | |
Dan Willemsen | 38f2dba | 2016-07-08 14:54:35 -0700 | [diff] [blame] | 61 | //go:noinline |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 62 | func useint(x uintptr) { |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 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 { |
Dan Willemsen | 38f2dba | 2016-07-08 14:54:35 -0700 | [diff] [blame] | 76 | big(x - 1) |
Brent Austin | ba3052e | 2015-04-21 16:08:23 -0700 | [diff] [blame] | 77 | } |
| 78 | } |