go/test/fixedbugs/issue27518a.go
Keith Randall 9dac0a8132 runtime: on a signal, set traceback address to a deferreturn call
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>
2018-10-03 19:54:23 +00:00

46 lines
1.1 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 nilp *int
var forceHeap interface{}
func main() {
// x is a pointer on the stack to heap-allocated memory.
x := new([32]*int)
forceHeap = x
forceHeap = nil
// Push a defer to be run when we panic below.
defer func() {
// Ignore the panic.
recover()
// Force a stack walk. Go 1.11 will fail because x is now
// considered live again.
runtime.GC()
}()
// Make x live at the defer's PC.
runtime.KeepAlive(x)
// x is no longer live. Garbage collect the [32]*int on the
// heap.
runtime.GC()
// At this point x's dead stack slot points to dead memory.
// Trigger a sigpanic. Since this is an implicit panic, we
// don't have an explicit liveness map here.
// Traceback used to use the liveness map of the most recent defer,
// but in that liveness map, x will be live again even though
// it points to dead memory. The fix is to use the liveness
// map of a deferreturn call instead.
*nilp = 0
}