mirror of
https://github.com/golang/go
synced 2024-11-25 09:47:57 -07:00
9dac0a8132
When a function triggers a signal (like a segfault which translates to a nil pointer exception) during execution, a sigpanic handler is just below it on the stack. The function itself did not stop at a safepoint, so we have to figure out what safepoint we should use to scan its stack frame. Previously we used the site of the most recent defer to get the live variables at the signal site. That answer is not quite correct, as explained in #27518. Instead, use the site of a deferreturn call. It has all the right variables marked as live (no args, all the return values, except those that escape to the heap, in which case the corresponding PAUTOHEAP variables will be live instead). This CL requires stack objects, so that all the local variables and args referenced by the deferred closures keep the right variables alive. Fixes #27518 Change-Id: Id45d8a8666759986c203181090b962e2981e48ca Reviewed-on: https://go-review.googlesource.com/c/134637 Reviewed-by: Austin Clements <austin@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com>
73 lines
1.2 KiB
Go
73 lines
1.2 KiB
Go
// run
|
|
|
|
// Copyright 2018 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 "runtime"
|
|
|
|
var finalized bool
|
|
var err string
|
|
|
|
type HeapObj [8]int64
|
|
|
|
const filler int64 = 0x123456789abcdef0
|
|
|
|
func (h *HeapObj) init() {
|
|
for i := 0; i < len(*h); i++ {
|
|
h[i] = filler
|
|
}
|
|
}
|
|
func (h *HeapObj) check() {
|
|
for i := 0; i < len(*h); i++ {
|
|
if h[i] != filler {
|
|
err = "filler overwritten"
|
|
}
|
|
}
|
|
}
|
|
|
|
type StackObj struct {
|
|
h *HeapObj
|
|
}
|
|
|
|
func gc(shouldFinalize bool) {
|
|
runtime.GC()
|
|
runtime.GC()
|
|
runtime.GC()
|
|
if shouldFinalize != finalized {
|
|
err = "heap object finalized at the wrong time"
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
var s StackObj
|
|
s.h = new(HeapObj)
|
|
s.h.init()
|
|
runtime.SetFinalizer(s.h, func(h *HeapObj) {
|
|
finalized = true
|
|
})
|
|
gc(false)
|
|
h := g(&s)
|
|
gc(false)
|
|
h.check()
|
|
gc(true) // finalize here, after return value's last use. (Go1.11 never runs the finalizer.)
|
|
if err != "" {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func g(p *StackObj) (v *HeapObj) {
|
|
gc(false)
|
|
v = p.h // last use of the stack object. the only reference to the heap object is in the return slot.
|
|
gc(false)
|
|
defer func() {
|
|
gc(false)
|
|
recover()
|
|
gc(false)
|
|
}()
|
|
*(*int)(nil) = 0
|
|
return
|
|
}
|