1// run 2 3// Copyright 2018 The Go Authors. All rights reserved. 4// Use of this source code is governed by a BSD-style 5// license that can be found in the LICENSE file. 6 7package main 8 9import "runtime" 10 11var finalized bool 12var err string 13 14type HeapObj [8]int64 15 16const filler int64 = 0x123456789abcdef0 17 18func (h *HeapObj) init() { 19 for i := 0; i < len(*h); i++ { 20 h[i] = filler 21 } 22} 23func (h *HeapObj) check() { 24 for i := 0; i < len(*h); i++ { 25 if h[i] != filler { 26 err = "filler overwritten" 27 } 28 } 29} 30 31type StackObj struct { 32 h *HeapObj 33} 34 35func gc(shouldFinalize bool) { 36 runtime.GC() 37 runtime.GC() 38 runtime.GC() 39 if shouldFinalize != finalized { 40 err = "heap object finalized at the wrong time" 41 } 42} 43 44func main() { 45 var s StackObj 46 s.h = new(HeapObj) 47 s.h.init() 48 runtime.SetFinalizer(s.h, func(h *HeapObj) { 49 finalized = true 50 }) 51 gc(false) 52 h := g(&s) 53 gc(false) 54 h.check() 55 gc(true) // finalize here, after return value's last use. (Go1.11 never runs the finalizer.) 56 if err != "" { 57 panic(err) 58 } 59} 60 61func g(p *StackObj) (v *HeapObj) { 62 gc(false) 63 v = p.h // last use of the stack object. the only reference to the heap object is in the return slot. 64 gc(false) 65 defer func() { 66 gc(false) 67 recover() 68 gc(false) 69 }() 70 *(*int)(nil) = 0 71 return 72} 73