1// run
2
3// Copyright 2016 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
7package main
8
9import (
10	"fmt"
11	"runtime"
12)
13
14var sink *[20]byte
15
16func f() (x [20]byte) {
17	// Initialize x.
18	for i := range x {
19		x[i] = byte(i)
20	}
21
22	// Force x to be allocated on the heap.
23	sink = &x
24	sink = nil
25
26	// Go to deferreturn after the panic below.
27	defer func() {
28		recover()
29	}()
30
31	// This call collects the heap-allocated version of x (oops!)
32	runtime.GC()
33
34	// Allocate that same object again and clobber it.
35	y := new([20]byte)
36	for i := 0; i < 20; i++ {
37		y[i] = 99
38	}
39	// Make sure y is heap allocated.
40	sink = y
41
42	panic(nil)
43
44	// After the recover we reach the deferreturn, which
45	// copies the heap version of x back to the stack.
46	// It gets the pointer to x from a stack slot that was
47	// not marked as live during the call to runtime.GC().
48}
49
50var sinkint int
51
52func g(p *int) (x [20]byte) {
53	// Initialize x.
54	for i := range x {
55		x[i] = byte(i)
56	}
57
58	// Force x to be allocated on the heap.
59	sink = &x
60	sink = nil
61
62	// Go to deferreturn after the panic below.
63	defer func() {
64		recover()
65	}()
66
67	// This call collects the heap-allocated version of x (oops!)
68	runtime.GC()
69
70	// Allocate that same object again and clobber it.
71	y := new([20]byte)
72	for i := 0; i < 20; i++ {
73		y[i] = 99
74	}
75	// Make sure y is heap allocated.
76	sink = y
77
78	// panic with a non-call (with no fallthrough)
79	for {
80		sinkint = *p
81	}
82
83	// After the recover we reach the deferreturn, which
84	// copies the heap version of x back to the stack.
85	// It gets the pointer to x from a stack slot that was
86	// not marked as live during the call to runtime.GC().
87}
88
89func main() {
90	x := f()
91	for i, v := range x {
92		if v != byte(i) {
93			fmt.Printf("%v\n", x)
94			panic("bad f")
95		}
96	}
97	x = g(nil)
98	for i, v := range x {
99		if v != byte(i) {
100			fmt.Printf("%v\n", x)
101			panic("bad g")
102		}
103	}
104}
105