blob: 723d5d9fa6cf6bec6467e52adec049722d1d58bb [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
7// Liveness calculations were wrong for a result parameter pushed onto
8// the heap in a function that used defer. Program would crash with
9// runtime: bad pointer in frame main.A at 0xc4201e6838: 0x1
10
11package main
12
13import "errors"
14
15var sink interface{}
16
17//go:noinline
18func f(err *error) {
19 if err != nil {
20 sink = err
21 }
22}
23
24//go:noinline
25func A(n, m int64) (res int64, err error) {
26 defer f(&err) // output parameter's address escapes to a defer.
27 if n < 0 {
28 err = errors.New("No negative")
29 return
30 }
31 if n <= 1 {
32 res = n
33 return
34 }
35 res = B(m) // This call to B drizzles a little junk on the stack.
36 res, err = A(n-1, m)
37 res++
38 return
39}
40
41// B does a little bit of recursion dribbling not-zero onto the stack.
42//go:noinline
43func B(n int64) (res int64) {
44 if n <= 1 { // Prefer to leave a 1 on the stack.
45 return n
46 }
47 return 1 + B(n-1)
48}
49
50func main() {
51 x, e := A(0, 0)
52 for j := 0; j < 4; j++ { // j controls amount of B's stack dribble
53 for i := 0; i < 1000; i++ { // try more and more recursion until stack growth occurs in newobject in prologue
54 x, e = A(int64(i), int64(j))
55 }
56 }
57 _, _ = x, e
58}