|  | // run | 
|  |  | 
|  | // Copyright 2019 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. | 
|  |  | 
|  | // Make sure we use the deferreturn live map instead of | 
|  | // the entry live map when handling a segv in a function | 
|  | // that defers. | 
|  |  | 
|  | 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" | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func gc(shouldFinalize bool) { | 
|  | runtime.GC() | 
|  | runtime.GC() | 
|  | runtime.GC() | 
|  | if shouldFinalize != finalized { | 
|  | err = "heap object finalized at the wrong time" | 
|  | } | 
|  | } | 
|  |  | 
|  | func main() { | 
|  | h := new(HeapObj) | 
|  | h.init() | 
|  | runtime.SetFinalizer(h, func(h *HeapObj) { | 
|  | finalized = true | 
|  | }) | 
|  |  | 
|  | gc(false) | 
|  | g(h) | 
|  | if err != "" { | 
|  | panic(err) | 
|  | } | 
|  | } | 
|  |  | 
|  | func g(h *HeapObj) { | 
|  | gc(false) | 
|  | h.check() | 
|  | // h is now unused | 
|  | defer func() { | 
|  | // h should not be live here. Previously we used to | 
|  | // use the function entry point as the place to get | 
|  | // the live map when handling a segv. | 
|  | gc(true) | 
|  | recover() | 
|  | }() | 
|  | *(*int)(nil) = 0 // trigger a segv | 
|  | return | 
|  | } |