Source file
src/runtime/mfinal_test.go
1
2
3
4
5 package runtime_test
6
7 import (
8 "runtime"
9 "testing"
10 "time"
11 "unsafe"
12 )
13
14 type Tintptr *int
15 type Tint int
16
17 func (t *Tint) m() {}
18
19 type Tinter interface {
20 m()
21 }
22
23 func TestFinalizerType(t *testing.T) {
24 ch := make(chan bool, 10)
25 finalize := func(x *int) {
26 if *x != 97531 {
27 t.Errorf("finalizer %d, want %d", *x, 97531)
28 }
29 ch <- true
30 }
31
32 var finalizerTests = []struct {
33 convert func(*int) any
34 finalizer any
35 }{
36 {func(x *int) any { return x }, func(v *int) { finalize(v) }},
37 {func(x *int) any { return Tintptr(x) }, func(v Tintptr) { finalize(v) }},
38 {func(x *int) any { return Tintptr(x) }, func(v *int) { finalize(v) }},
39 {func(x *int) any { return (*Tint)(x) }, func(v *Tint) { finalize((*int)(v)) }},
40 {func(x *int) any { return (*Tint)(x) }, func(v Tinter) { finalize((*int)(v.(*Tint))) }},
41
42
43
44
45 {func(x *int) any { return x }, func(v any) [4]int64 {
46 print()
47 finalize(v.(*int))
48 return [4]int64{}
49 }},
50 }
51
52 for _, tt := range finalizerTests {
53 done := make(chan bool, 1)
54 go func() {
55
56
57
58 type T struct {
59 v int
60 p unsafe.Pointer
61 }
62 v := &new(T).v
63 *v = 97531
64 runtime.SetFinalizer(tt.convert(v), tt.finalizer)
65 v = nil
66 done <- true
67 }()
68 <-done
69 runtime.GC()
70 <-ch
71 }
72 }
73
74 type bigValue struct {
75 fill uint64
76 it bool
77 up string
78 }
79
80 func TestFinalizerInterfaceBig(t *testing.T) {
81 ch := make(chan bool)
82 done := make(chan bool, 1)
83 go func() {
84 v := &bigValue{0xDEADBEEFDEADBEEF, true, "It matters not how strait the gate"}
85 old := *v
86 runtime.SetFinalizer(v, func(v any) {
87 i, ok := v.(*bigValue)
88 if !ok {
89 t.Errorf("finalizer called with type %T, want *bigValue", v)
90 }
91 if *i != old {
92 t.Errorf("finalizer called with %+v, want %+v", *i, old)
93 }
94 close(ch)
95 })
96 v = nil
97 done <- true
98 }()
99 <-done
100 runtime.GC()
101 <-ch
102 }
103
104 func fin(v *int) {
105 }
106
107
108 func TestFinalizerZeroSizedStruct(t *testing.T) {
109 type Z struct{}
110 z := new(Z)
111 runtime.SetFinalizer(z, func(*Z) {})
112 }
113
114 func BenchmarkFinalizer(b *testing.B) {
115 const Batch = 1000
116 b.RunParallel(func(pb *testing.PB) {
117 var data [Batch]*int
118 for i := 0; i < Batch; i++ {
119 data[i] = new(int)
120 }
121 for pb.Next() {
122 for i := 0; i < Batch; i++ {
123 runtime.SetFinalizer(data[i], fin)
124 }
125 for i := 0; i < Batch; i++ {
126 runtime.SetFinalizer(data[i], nil)
127 }
128 }
129 })
130 }
131
132 func BenchmarkFinalizerRun(b *testing.B) {
133 b.RunParallel(func(pb *testing.PB) {
134 for pb.Next() {
135 v := new(int)
136 runtime.SetFinalizer(v, fin)
137 }
138 })
139 }
140
141
142
143
144
145 const objsize = 320
146
147 type objtype [objsize]byte
148
149 func adjChunks() (*objtype, *objtype) {
150 var s []*objtype
151
152 for {
153 c := new(objtype)
154 for _, d := range s {
155 if uintptr(unsafe.Pointer(c))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(d)) {
156 return c, d
157 }
158 if uintptr(unsafe.Pointer(d))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(c)) {
159 return d, c
160 }
161 }
162 s = append(s, c)
163 }
164 }
165
166
167 func TestEmptySlice(t *testing.T) {
168 x, y := adjChunks()
169
170
171 xs := x[objsize:]
172
173 fin := make(chan bool, 1)
174 runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
175 runtime.GC()
176 <-fin
177 xsglobal = xs
178 }
179
180 var xsglobal []byte
181
182 func adjStringChunk() (string, *objtype) {
183 b := make([]byte, objsize)
184 for {
185 s := string(b)
186 t := new(objtype)
187 p := *(*uintptr)(unsafe.Pointer(&s))
188 q := uintptr(unsafe.Pointer(t))
189 if p+objsize == q {
190 return s, t
191 }
192 }
193 }
194
195
196 func TestEmptyString(t *testing.T) {
197 x, y := adjStringChunk()
198
199 ss := x[objsize:]
200 fin := make(chan bool, 1)
201
202 runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
203 runtime.GC()
204 <-fin
205 ssglobal = ss
206 }
207
208 var ssglobal string
209
210
211 func TestFinalizerOnGlobal(t *testing.T) {
212 runtime.SetFinalizer(Foo1, func(p *Object1) {})
213 runtime.SetFinalizer(Foo2, func(p *Object2) {})
214 runtime.SetFinalizer(Foo1, nil)
215 runtime.SetFinalizer(Foo2, nil)
216 }
217
218 type Object1 struct {
219 Something []byte
220 }
221
222 type Object2 struct {
223 Something byte
224 }
225
226 var (
227 Foo2 = &Object2{}
228 Foo1 = &Object1{}
229 )
230
231 func TestDeferKeepAlive(t *testing.T) {
232 if *flagQuick {
233 t.Skip("-quick")
234 }
235
236
237 t.Parallel()
238 type T *int
239 x := new(T)
240 finRun := false
241 runtime.SetFinalizer(x, func(x *T) {
242 finRun = true
243 })
244 defer runtime.KeepAlive(x)
245 runtime.GC()
246 time.Sleep(time.Second)
247 if finRun {
248 t.Errorf("finalizer ran prematurely")
249 }
250 }
251
View as plain text