diff options
Diffstat (limited to '')
-rw-r--r-- | test/fixedbugs/issue16095.go | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/test/fixedbugs/issue16095.go b/test/fixedbugs/issue16095.go new file mode 100644 index 0000000..864b4b7 --- /dev/null +++ b/test/fixedbugs/issue16095.go @@ -0,0 +1,104 @@ +// 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") + } + } +} |