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

     1  // run
     2  
     3  // Copyright 2014 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  // The liveness code used to say that, in func g, s was live
     8  // starting at its declaration, because it appears to have its
     9  // address taken by the closure (different s, but the parser
    10  // gets slightly confused, a separate bug). The liveness analysis
    11  // saw s as having its address taken but the register optimizer
    12  // did not. This mismatch meant that s would be marked live
    13  // (and therefore initialized) at the call to f, but the register optimizer
    14  // would optimize away the initialization of s before f, causing the
    15  // garbage collector to use unused data.
    16  // The register optimizer has been changed to respect the
    17  // same "address taken" flag that the liveness analysis uses,
    18  // even if it cannot see any address being taken in the actual
    19  // machine code. This is conservative but keeps the two consistent,
    20  // which is the most important thing.
    21  
    22  package main
    23  
    24  import "runtime"
    25  
    26  //go:noinline
    27  func f() interface{} {
    28  	runtime.GC()
    29  	return nil
    30  }
    31  
    32  //go:noinline
    33  func g() {
    34  	var s interface{}
    35  	_ = func() {
    36  		s := f()
    37  		_ = s
    38  	}
    39  	s = f()
    40  	useiface(s)
    41  	useiface(s)
    42  }
    43  
    44  //go:noinline
    45  func useiface(x interface{}) {
    46  }
    47  
    48  //go:noinline
    49  func h() {
    50  	var x [16]uintptr
    51  	for i := range x {
    52  		x[i] = 1
    53  	}
    54  
    55  	useint(x[0])
    56  	useint(x[1])
    57  	useint(x[2])
    58  	useint(x[3])
    59  }
    60  
    61  //go:noinline
    62  func useint(x uintptr) {
    63  }
    64  
    65  func main() {
    66  	// scribble non-zero values on stack
    67  	h()
    68  	// call function that used to let the garbage collector
    69  	// see uninitialized stack values; it will see the
    70  	// nonzero values.
    71  	g()
    72  }
    73  
    74  func big(x int) {
    75  	if x >= 0 {
    76  		big(x - 1)
    77  	}
    78  }