| // run | |
| // 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 main | |
| import ( | |
| "fmt" | |
| "runtime" | |
| ) | |
| var sink *[20]byte | |
| func f() (x [20]byte) { | |
| // Initialize x. | |
| for i := range x { | |
| x[i] = byte(i) | |
| } | |
| // Force x to be allocated on the heap. | |
| sink = &x | |
| sink = nil | |
| // Go to deferreturn after the panic below. | |
| defer func() { | |
| recover() | |
| }() | |
| // This call collects the heap-allocated version of x (oops!) | |
| runtime.GC() | |
| // Allocate that same object again and clobber it. | |
| y := new([20]byte) | |
| for i := 0; i < 20; i++ { | |
| y[i] = 99 | |
| } | |
| // Make sure y is heap allocated. | |
| sink = y | |
| panic(nil) | |
| // After the recover we reach the deferreturn, which | |
| // copies the heap version of x back to the stack. | |
| // It gets the pointer to x from a stack slot that was | |
| // not marked as live during the call to runtime.GC(). | |
| } | |
| var sinkint int | |
| func g(p *int) (x [20]byte) { | |
| // Initialize x. | |
| for i := range x { | |
| x[i] = byte(i) | |
| } | |
| // Force x to be allocated on the heap. | |
| sink = &x | |
| sink = nil | |
| // Go to deferreturn after the panic below. | |
| defer func() { | |
| recover() | |
| }() | |
| // This call collects the heap-allocated version of x (oops!) | |
| runtime.GC() | |
| // Allocate that same object again and clobber it. | |
| y := new([20]byte) | |
| for i := 0; i < 20; i++ { | |
| y[i] = 99 | |
| } | |
| // Make sure y is heap allocated. | |
| sink = y | |
| // panic with a non-call (with no fallthrough) | |
| for { | |
| sinkint = *p | |
| } | |
| // After the recover we reach the deferreturn, which | |
| // copies the heap version of x back to the stack. | |
| // It gets the pointer to x from a stack slot that was | |
| // not marked as live during the call to runtime.GC(). | |
| } | |
| func main() { | |
| x := f() | |
| for i, v := range x { | |
| if v != byte(i) { | |
| fmt.Printf("%v\n", x) | |
| panic("bad f") | |
| } | |
| } | |
| x = g(nil) | |
| for i, v := range x { | |
| if v != byte(i) { | |
| fmt.Printf("%v\n", x) | |
| panic("bad g") | |
| } | |
| } | |
| } |