]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/defer_test.go
cmd/compile/internal/inline: score call sites exposed by inlines
[gostls13.git] / src / runtime / defer_test.go
1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package runtime_test
6
7 import (
8         "reflect"
9         "runtime"
10         "testing"
11 )
12
13 // Make sure open-coded defer exit code is not lost, even when there is an
14 // unconditional panic (hence no return from the function)
15 func TestUnconditionalPanic(t *testing.T) {
16         defer func() {
17                 if recover() != "testUnconditional" {
18                         t.Fatal("expected unconditional panic")
19                 }
20         }()
21         panic("testUnconditional")
22 }
23
24 var glob int = 3
25
26 // Test an open-coded defer and non-open-coded defer - make sure both defers run
27 // and call recover()
28 func TestOpenAndNonOpenDefers(t *testing.T) {
29         for {
30                 // Non-open defer because in a loop
31                 defer func(n int) {
32                         if recover() != "testNonOpenDefer" {
33                                 t.Fatal("expected testNonOpen panic")
34                         }
35                 }(3)
36                 if glob > 2 {
37                         break
38                 }
39         }
40         testOpen(t, 47)
41         panic("testNonOpenDefer")
42 }
43
44 //go:noinline
45 func testOpen(t *testing.T, arg int) {
46         defer func(n int) {
47                 if recover() != "testOpenDefer" {
48                         t.Fatal("expected testOpen panic")
49                 }
50         }(4)
51         if arg > 2 {
52                 panic("testOpenDefer")
53         }
54 }
55
56 // Test a non-open-coded defer and an open-coded defer - make sure both defers run
57 // and call recover()
58 func TestNonOpenAndOpenDefers(t *testing.T) {
59         testOpen(t, 47)
60         for {
61                 // Non-open defer because in a loop
62                 defer func(n int) {
63                         if recover() != "testNonOpenDefer" {
64                                 t.Fatal("expected testNonOpen panic")
65                         }
66                 }(3)
67                 if glob > 2 {
68                         break
69                 }
70         }
71         panic("testNonOpenDefer")
72 }
73
74 var list []int
75
76 // Make sure that conditional open-coded defers are activated correctly and run in
77 // the correct order.
78 func TestConditionalDefers(t *testing.T) {
79         list = make([]int, 0, 10)
80
81         defer func() {
82                 if recover() != "testConditional" {
83                         t.Fatal("expected panic")
84                 }
85                 want := []int{4, 2, 1}
86                 if !reflect.DeepEqual(want, list) {
87                         t.Fatalf("wanted %v, got %v", want, list)
88                 }
89
90         }()
91         testConditionalDefers(8)
92 }
93
94 func testConditionalDefers(n int) {
95         doappend := func(i int) {
96                 list = append(list, i)
97         }
98
99         defer doappend(1)
100         if n > 5 {
101                 defer doappend(2)
102                 if n > 8 {
103                         defer doappend(3)
104                 } else {
105                         defer doappend(4)
106                 }
107         }
108         panic("testConditional")
109 }
110
111 // Test that there is no compile-time or run-time error if an open-coded defer
112 // call is removed by constant propagation and dead-code elimination.
113 func TestDisappearingDefer(t *testing.T) {
114         switch runtime.GOOS {
115         case "invalidOS":
116                 defer func() {
117                         t.Fatal("Defer shouldn't run")
118                 }()
119         }
120 }
121
122 // This tests an extra recursive panic behavior that is only specified in the
123 // code. Suppose a first panic P1 happens and starts processing defer calls. If a
124 // second panic P2 happens while processing defer call D in frame F, then defer
125 // call processing is restarted (with some potentially new defer calls created by
126 // D or its callees). If the defer processing reaches the started defer call D
127 // again in the defer stack, then the original panic P1 is aborted and cannot
128 // continue panic processing or be recovered. If the panic P2 does a recover at
129 // some point, it will naturally remove the original panic P1 from the stack
130 // (since the original panic had to be in frame F or a descendant of F).
131 func TestAbortedPanic(t *testing.T) {
132         defer func() {
133                 r := recover()
134                 if r != nil {
135                         t.Fatalf("wanted nil recover, got %v", r)
136                 }
137         }()
138         defer func() {
139                 r := recover()
140                 if r != "panic2" {
141                         t.Fatalf("wanted %v, got %v", "panic2", r)
142                 }
143         }()
144         defer func() {
145                 panic("panic2")
146         }()
147         panic("panic1")
148 }
149
150 // This tests that recover() does not succeed unless it is called directly from a
151 // defer function that is directly called by the panic.  Here, we first call it
152 // from a defer function that is created by the defer function called directly by
153 // the panic.  In
154 func TestRecoverMatching(t *testing.T) {
155         defer func() {
156                 r := recover()
157                 if r != "panic1" {
158                         t.Fatalf("wanted %v, got %v", "panic1", r)
159                 }
160         }()
161         defer func() {
162                 defer func() {
163                         // Shouldn't succeed, even though it is called directly
164                         // from a defer function, since this defer function was
165                         // not directly called by the panic.
166                         r := recover()
167                         if r != nil {
168                                 t.Fatalf("wanted nil recover, got %v", r)
169                         }
170                 }()
171         }()
172         panic("panic1")
173 }
174
175 type nonSSAable [128]byte
176
177 type bigStruct struct {
178         x, y, z, w, p, q int64
179 }
180
181 type containsBigStruct struct {
182         element bigStruct
183 }
184
185 func mknonSSAable() nonSSAable {
186         globint1++
187         return nonSSAable{0, 0, 0, 0, 5}
188 }
189
190 var globint1, globint2, globint3 int
191
192 //go:noinline
193 func sideeffect(n int64) int64 {
194         globint2++
195         return n
196 }
197
198 func sideeffect2(in containsBigStruct) containsBigStruct {
199         globint3++
200         return in
201 }
202
203 // Test that nonSSAable arguments to defer are handled correctly and only evaluated once.
204 func TestNonSSAableArgs(t *testing.T) {
205         globint1 = 0
206         globint2 = 0
207         globint3 = 0
208         var save1 byte
209         var save2 int64
210         var save3 int64
211         var save4 int64
212
213         defer func() {
214                 if globint1 != 1 {
215                         t.Fatalf("globint1:  wanted: 1, got %v", globint1)
216                 }
217                 if save1 != 5 {
218                         t.Fatalf("save1:  wanted: 5, got %v", save1)
219                 }
220                 if globint2 != 1 {
221                         t.Fatalf("globint2:  wanted: 1, got %v", globint2)
222                 }
223                 if save2 != 2 {
224                         t.Fatalf("save2:  wanted: 2, got %v", save2)
225                 }
226                 if save3 != 4 {
227                         t.Fatalf("save3:  wanted: 4, got %v", save3)
228                 }
229                 if globint3 != 1 {
230                         t.Fatalf("globint3:  wanted: 1, got %v", globint3)
231                 }
232                 if save4 != 4 {
233                         t.Fatalf("save1:  wanted: 4, got %v", save4)
234                 }
235         }()
236
237         // Test function returning a non-SSAable arg
238         defer func(n nonSSAable) {
239                 save1 = n[4]
240         }(mknonSSAable())
241         // Test composite literal that is not SSAable
242         defer func(b bigStruct) {
243                 save2 = b.y
244         }(bigStruct{1, 2, 3, 4, 5, sideeffect(6)})
245
246         // Test struct field reference that is non-SSAable
247         foo := containsBigStruct{}
248         foo.element.z = 4
249         defer func(element bigStruct) {
250                 save3 = element.z
251         }(foo.element)
252         defer func(element bigStruct) {
253                 save4 = element.z
254         }(sideeffect2(foo).element)
255 }
256
257 //go:noinline
258 func doPanic() {
259         panic("Test panic")
260 }
261
262 func TestDeferForFuncWithNoExit(t *testing.T) {
263         cond := 1
264         defer func() {
265                 if cond != 2 {
266                         t.Fatalf("cond: wanted 2, got %v", cond)
267                 }
268                 if recover() != "Test panic" {
269                         t.Fatal("Didn't find expected panic")
270                 }
271         }()
272         x := 0
273         // Force a stack copy, to make sure that the &cond pointer passed to defer
274         // function is properly updated.
275         growStackIter(&x, 1000)
276         cond = 2
277         doPanic()
278
279         // This function has no exit/return, since it ends with an infinite loop
280         for {
281         }
282 }
283
284 // Test case approximating issue #37664, where a recursive function (interpreter)
285 // may do repeated recovers/re-panics until it reaches the frame where the panic
286 // can actually be handled. The recurseFnPanicRec() function is testing that there
287 // are no stale defer structs on the defer chain after the interpreter() sequence,
288 // by writing a bunch of 0xffffffffs into several recursive stack frames, and then
289 // doing a single panic-recover which would invoke any such stale defer structs.
290 func TestDeferWithRepeatedRepanics(t *testing.T) {
291         interpreter(0, 6, 2)
292         recurseFnPanicRec(0, 10)
293         interpreter(0, 5, 1)
294         recurseFnPanicRec(0, 10)
295         interpreter(0, 6, 3)
296         recurseFnPanicRec(0, 10)
297 }
298
299 func interpreter(level int, maxlevel int, rec int) {
300         defer func() {
301                 e := recover()
302                 if e == nil {
303                         return
304                 }
305                 if level != e.(int) {
306                         //fmt.Fprintln(os.Stderr, "re-panicing, level", level)
307                         panic(e)
308                 }
309                 //fmt.Fprintln(os.Stderr, "Recovered, level", level)
310         }()
311         if level+1 < maxlevel {
312                 interpreter(level+1, maxlevel, rec)
313         } else {
314                 //fmt.Fprintln(os.Stderr, "Initiating panic")
315                 panic(rec)
316         }
317 }
318
319 func recurseFnPanicRec(level int, maxlevel int) {
320         defer func() {
321                 recover()
322         }()
323         recurseFn(level, maxlevel)
324 }
325
326 var saveInt uint32
327
328 func recurseFn(level int, maxlevel int) {
329         a := [40]uint32{0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}
330         if level+1 < maxlevel {
331                 // Make sure a array is referenced, so it is not optimized away
332                 saveInt = a[4]
333                 recurseFn(level+1, maxlevel)
334         } else {
335                 panic("recurseFn panic")
336         }
337 }
338
339 // Try to reproduce issue #37688, where a pointer to an open-coded defer struct is
340 // mistakenly held, and that struct keeps a pointer to a stack-allocated defer
341 // struct, and that stack-allocated struct gets overwritten or the stack gets
342 // moved, so a memory error happens on GC.
343 func TestIssue37688(t *testing.T) {
344         for j := 0; j < 10; j++ {
345                 g2()
346                 g3()
347         }
348 }
349
350 type foo struct {
351 }
352
353 //go:noinline
354 func (f *foo) method1() {
355 }
356
357 //go:noinline
358 func (f *foo) method2() {
359 }
360
361 func g2() {
362         var a foo
363         ap := &a
364         // The loop forces this defer to be heap-allocated and the remaining two
365         // to be stack-allocated.
366         for i := 0; i < 1; i++ {
367                 defer ap.method1()
368         }
369         defer ap.method2()
370         defer ap.method1()
371         ff1(ap, 1, 2, 3, 4, 5, 6, 7, 8, 9)
372         // Try to get the stack to be moved by growing it too large, so
373         // existing stack-allocated defer becomes invalid.
374         rec1(2000)
375 }
376
377 func g3() {
378         // Mix up the stack layout by adding in an extra function frame
379         g2()
380 }
381
382 var globstruct struct {
383         a, b, c, d, e, f, g, h, i int
384 }
385
386 func ff1(ap *foo, a, b, c, d, e, f, g, h, i int) {
387         defer ap.method1()
388
389         // Make a defer that has a very large set of args, hence big size for the
390         // defer record for the open-coded frame (which means it won't use the
391         // defer pool)
392         defer func(ap *foo, a, b, c, d, e, f, g, h, i int) {
393                 if v := recover(); v != nil {
394                 }
395                 globstruct.a = a
396                 globstruct.b = b
397                 globstruct.c = c
398                 globstruct.d = d
399                 globstruct.e = e
400                 globstruct.f = f
401                 globstruct.g = g
402                 globstruct.h = h
403         }(ap, a, b, c, d, e, f, g, h, i)
404         panic("ff1 panic")
405 }
406
407 func rec1(max int) {
408         if max > 0 {
409                 rec1(max - 1)
410         }
411 }
412
413 func TestIssue43921(t *testing.T) {
414         defer func() {
415                 expect(t, 1, recover())
416         }()
417         func() {
418                 // Prevent open-coded defers
419                 for {
420                         defer func() {}()
421                         break
422                 }
423
424                 defer func() {
425                         defer func() {
426                                 expect(t, 4, recover())
427                         }()
428                         panic(4)
429                 }()
430                 panic(1)
431
432         }()
433 }
434
435 func expect(t *testing.T, n int, err any) {
436         if n != err {
437                 t.Fatalf("have %v, want %v", err, n)
438         }
439 }
440
441 func TestIssue43920(t *testing.T) {
442         var steps int
443
444         defer func() {
445                 expect(t, 1, recover())
446         }()
447         defer func() {
448                 defer func() {
449                         defer func() {
450                                 expect(t, 5, recover())
451                         }()
452                         defer panic(5)
453                         func() {
454                                 panic(4)
455                         }()
456                 }()
457                 defer func() {
458                         expect(t, 3, recover())
459                 }()
460                 defer panic(3)
461         }()
462         func() {
463                 defer step(t, &steps, 1)
464                 panic(1)
465         }()
466 }
467
468 func step(t *testing.T, steps *int, want int) {
469         *steps++
470         if *steps != want {
471                 t.Fatalf("have %v, want %v", *steps, want)
472         }
473 }
474
475 func TestIssue43941(t *testing.T) {
476         var steps int = 7
477         defer func() {
478                 step(t, &steps, 14)
479                 expect(t, 4, recover())
480         }()
481         func() {
482                 func() {
483                         defer func() {
484                                 defer func() {
485                                         expect(t, 3, recover())
486                                 }()
487                                 defer panic(3)
488                                 panic(2)
489                         }()
490                         defer func() {
491                                 expect(t, 1, recover())
492                         }()
493                         defer panic(1)
494                 }()
495                 defer func() {}()
496                 defer func() {}()
497                 defer step(t, &steps, 10)
498                 defer step(t, &steps, 9)
499                 step(t, &steps, 8)
500         }()
501         func() {
502                 defer step(t, &steps, 13)
503                 defer step(t, &steps, 12)
504                 func() {
505                         defer step(t, &steps, 11)
506                         panic(4)
507                 }()
508
509                 // Code below isn't executed,
510                 // but removing it breaks the test case.
511                 defer func() {}()
512                 defer panic(-1)
513                 defer step(t, &steps, -1)
514                 defer step(t, &steps, -1)
515                 defer func() {}()
516         }()
517 }