// run // Copyright 2014 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. // Issue 8048. Incorrect handling of liveness when walking stack // containing faulting frame. package main import "runtime" func main() { test1() test2() test3() } func test1() { // test1f will panic without its own defer. // The runtime.GC checks that we can walk the stack // at that point and not get confused. // The recover lets test1 exit normally. defer func() { runtime.GC() recover() }() test1f() } func test1f() { // Because b == false, the if does not execute, // so x == nil, so the println(*x) faults reading // from nil. The compiler will lay out the code // so that the if body occurs above the *x, // so if the liveness info at the *x is used, it will // find the liveness at the call to runtime.GC. // It will think y is live, but y is uninitialized, // and the runtime will crash detecting a bad slice. // The runtime should see that there are no defers // corresponding to this panicked frame and ignore // the frame entirely. var x *int var b bool if b { y := make([]int, 1) runtime.GC() x = &y[0] } println(*x) } func test2() { // Same as test1, but the fault happens in the function with the defer. // The runtime should see the defer and garbage collect the frame // as if the PC were immediately after the defer statement. defer func() { runtime.GC() recover() }() var x *int var b bool if b { y := make([]int, 1) runtime.GC() x = &y[0] } println(*x) } func test3() { // Like test1 but avoid array index, which does not // move to end of function on ARM. defer func() { runtime.GC() recover() }() test3setup() test3f() } func test3setup() { var x uintptr var b bool b = true if b { y := uintptr(123) runtime.GC() x = y } runtime.GC() globl = x } var globl uintptr func test3f() { var x *int var b bool if b { y := new(int) runtime.GC() x = y } println(*x) }