1// run
2
3// Copyright 2023 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 (
10	"runtime"
11	"unsafe"
12)
13
14//go:noinline
15func g(x *byte) *byte { return x }
16
17func main() {
18	slice()
19	str("AAAAAAAA", "BBBBBBBBB")
20}
21
22func wait(done <-chan struct{}) bool {
23	for i := 0; i < 10; i++ {
24		runtime.GC()
25		select {
26		case <-done:
27			return true
28		default:
29		}
30	}
31	return false
32}
33
34func slice() {
35	s := make([]byte, 100)
36	s[0] = 1
37	one := unsafe.SliceData(s)
38
39	done := make(chan struct{})
40	runtime.SetFinalizer(one, func(*byte) { close(done) })
41
42	h := g(one)
43
44	if wait(done) {
45		panic("GC'd early")
46	}
47
48	if *h != 1 {
49		panic("lost one")
50	}
51
52	if !wait(done) {
53		panic("never GC'd")
54	}
55}
56
57var strDone = make(chan struct{})
58
59//go:noinline
60func str(x, y string) {
61	s := x + y // put in temporary on stack
62	p := unsafe.StringData(s)
63	runtime.SetFinalizer(p, func(*byte) { close(strDone) })
64
65	if wait(strDone) {
66		panic("GC'd early")
67	}
68
69	if *p != 'A' {
70		panic("lost p")
71	}
72
73	if !wait(strDone) {
74		panic("never GC'd")
75	}
76}
77