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
5package runtime_test
6
7import (
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)
15func TestUnconditionalPanic(t *testing.T) {
16	defer func() {
17		if recover() != "testUnconditional" {
18			t.Fatal("expected unconditional panic")
19		}
20	}()
21	panic("testUnconditional")
22}
23
24var glob int = 3
25
26// Test an open-coded defer and non-open-coded defer - make sure both defers run
27// and call recover()
28func 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
45func 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()
58func 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
74var list []int
75
76// Make sure that conditional open-coded defers are activated correctly and run in
77// the correct order.
78func 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
94func 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.
113func 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).
131func 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
154func 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
175type nonSSAable [128]byte
176
177type bigStruct struct {
178	x, y, z, w, p, q int64
179}
180
181type containsBigStruct struct {
182	element bigStruct
183}
184
185func mknonSSAable() nonSSAable {
186	globint1++
187	return nonSSAable{0, 0, 0, 0, 5}
188}
189
190var globint1, globint2, globint3 int
191
192//go:noinline
193func sideeffect(n int64) int64 {
194	globint2++
195	return n
196}
197
198func 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.
204func 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
258func doPanic() {
259	panic("Test panic")
260}
261
262func 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.
290func 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
299func 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
319func recurseFnPanicRec(level int, maxlevel int) {
320	defer func() {
321		recover()
322	}()
323	recurseFn(level, maxlevel)
324}
325
326var saveInt uint32
327
328func 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.
343func TestIssue37688(t *testing.T) {
344	for j := 0; j < 10; j++ {
345		g2()
346		g3()
347	}
348}
349
350type foo struct {
351}
352
353//go:noinline
354func (f *foo) method1() {
355}
356
357//go:noinline
358func (f *foo) method2() {
359}
360
361func 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
377func g3() {
378	// Mix up the stack layout by adding in an extra function frame
379	g2()
380}
381
382var globstruct struct {
383	a, b, c, d, e, f, g, h, i int
384}
385
386func 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
407func rec1(max int) {
408	if max > 0 {
409		rec1(max - 1)
410	}
411}
412
413func 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
435func expect(t *testing.T, n int, err any) {
436	if n != err {
437		t.Fatalf("have %v, want %v", err, n)
438	}
439}
440
441func 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
468func 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
475func 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}
518