mirror of
https://github.com/golang/go
synced 2024-11-23 19:30:05 -07:00
14d2ee1d00
The 'continuation pc' is where the frame will continue execution, if anywhere. For a frame that stopped execution due to a CALL instruction, the continuation pc is immediately after the CALL. But for a frame that stopped execution due to a fault, the continuation pc is the pc after the most recent CALL to deferproc in that frame, or else 0. That is where execution will continue, if anywhere. The liveness information is only recorded for CALL instructions. This change makes sure that we never look for liveness information except for CALL instructions. Using a valid PC fixes crashes when a garbage collection or stack copying tries to process a stack frame that has faulted. Record continuation pc in heapdump (format change). Fixes #8048. LGTM=iant, khr R=khr, iant, dvyukov CC=golang-codereviews, r https://golang.org/cl/100870044
108 lines
2.0 KiB
Go
108 lines
2.0 KiB
Go
// 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)
|
|
}
|