modernc.org/gc@v1.0.1-0.20240304020402-f0dba7c97c2b/testdata/errchk/test/fixedbugs/issue16249.go (about)

     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  }