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