Home | History | Annotate | Download | only in fixedbugs
      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 package main
      8 
      9 import (
     10 	"fmt"
     11 	"runtime"
     12 )
     13 
     14 var sink *[20]byte
     15 
     16 func 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 
     50 var sinkint int
     51 
     52 func 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 
     89 func 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 }
    105