// 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") } } }