mirror of
https://github.com/golang/go
synced 2024-11-23 14:40:02 -07:00
105 lines
1.9 KiB
Go
105 lines
1.9 KiB
Go
|
// run
|
||
|
|
||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
package main
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"runtime"
|
||
|
)
|
||
|
|
||
|
var sink *[20]byte
|
||
|
|
||
|
func f() (x [20]byte) {
|
||
|
// Initialize x.
|
||
|
for i := range x {
|
||
|
x[i] = byte(i)
|
||
|
}
|
||
|
|
||
|
// Force x to be allocated on the heap.
|
||
|
sink = &x
|
||
|
sink = nil
|
||
|
|
||
|
// Go to deferreturn after the panic below.
|
||
|
defer func() {
|
||
|
recover()
|
||
|
}()
|
||
|
|
||
|
// This call collects the heap-allocated version of x (oops!)
|
||
|
runtime.GC()
|
||
|
|
||
|
// Allocate that same object again and clobber it.
|
||
|
y := new([20]byte)
|
||
|
for i := 0; i < 20; i++ {
|
||
|
y[i] = 99
|
||
|
}
|
||
|
// Make sure y is heap allocated.
|
||
|
sink = y
|
||
|
|
||
|
panic(nil)
|
||
|
|
||
|
// After the recover we reach the deferreturn, which
|
||
|
// copies the heap version of x back to the stack.
|
||
|
// It gets the pointer to x from a stack slot that was
|
||
|
// not marked as live during the call to runtime.GC().
|
||
|
}
|
||
|
|
||
|
var sinkint int
|
||
|
|
||
|
func g(p *int) (x [20]byte) {
|
||
|
// Initialize x.
|
||
|
for i := range x {
|
||
|
x[i] = byte(i)
|
||
|
}
|
||
|
|
||
|
// Force x to be allocated on the heap.
|
||
|
sink = &x
|
||
|
sink = nil
|
||
|
|
||
|
// Go to deferreturn after the panic below.
|
||
|
defer func() {
|
||
|
recover()
|
||
|
}()
|
||
|
|
||
|
// This call collects the heap-allocated version of x (oops!)
|
||
|
runtime.GC()
|
||
|
|
||
|
// Allocate that same object again and clobber it.
|
||
|
y := new([20]byte)
|
||
|
for i := 0; i < 20; i++ {
|
||
|
y[i] = 99
|
||
|
}
|
||
|
// Make sure y is heap allocated.
|
||
|
sink = y
|
||
|
|
||
|
// panic with a non-call (with no fallthrough)
|
||
|
for {
|
||
|
sinkint = *p
|
||
|
}
|
||
|
|
||
|
// After the recover we reach the deferreturn, which
|
||
|
// copies the heap version of x back to the stack.
|
||
|
// It gets the pointer to x from a stack slot that was
|
||
|
// not marked as live during the call to runtime.GC().
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
x := f()
|
||
|
for i, v := range x {
|
||
|
if v != byte(i) {
|
||
|
fmt.Printf("%v\n", x)
|
||
|
panic("bad f")
|
||
|
}
|
||
|
}
|
||
|
x = g(nil)
|
||
|
for i, v := range x {
|
||
|
if v != byte(i) {
|
||
|
fmt.Printf("%v\n", x)
|
||
|
panic("bad g")
|
||
|
}
|
||
|
}
|
||
|
}
|