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