blob: 864b4b7c7cfcb29e182f2432c2edfa8d3d213b8a [file] [log] [blame]
Dan Willemsen38f2dba2016-07-08 14:54:35 -07001// 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}