Source file test/fixedbugs/issue16249.go
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 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 11 package main 12 13 import "errors" 14 15 var sink interface{} 16 17 //go:noinline 18 func f(err *error) { 19 if err != nil { 20 sink = err 21 } 22 } 23 24 //go:noinline 25 func 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 43 func 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 50 func 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 } 59