1// Copyright 2015 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 main
6
7import (
8	"fmt"
9	"runtime"
10	"runtime/debug"
11	"time"
12)
13
14func init() {
15	registerInit("InitDeadlock", InitDeadlock)
16	registerInit("NoHelperGoroutines", NoHelperGoroutines)
17
18	register("SimpleDeadlock", SimpleDeadlock)
19	register("LockedDeadlock", LockedDeadlock)
20	register("LockedDeadlock2", LockedDeadlock2)
21	register("GoexitDeadlock", GoexitDeadlock)
22	register("StackOverflow", StackOverflow)
23	register("ThreadExhaustion", ThreadExhaustion)
24	register("RecursivePanic", RecursivePanic)
25	register("RecursivePanic2", RecursivePanic2)
26	register("RecursivePanic3", RecursivePanic3)
27	register("RecursivePanic4", RecursivePanic4)
28	register("RecursivePanic5", RecursivePanic5)
29	register("GoexitExit", GoexitExit)
30	register("GoNil", GoNil)
31	register("MainGoroutineID", MainGoroutineID)
32	register("Breakpoint", Breakpoint)
33	register("GoexitInPanic", GoexitInPanic)
34	register("PanicAfterGoexit", PanicAfterGoexit)
35	register("RecoveredPanicAfterGoexit", RecoveredPanicAfterGoexit)
36	register("RecoverBeforePanicAfterGoexit", RecoverBeforePanicAfterGoexit)
37	register("RecoverBeforePanicAfterGoexit2", RecoverBeforePanicAfterGoexit2)
38	register("PanicTraceback", PanicTraceback)
39	register("GoschedInPanic", GoschedInPanic)
40	register("SyscallInPanic", SyscallInPanic)
41	register("PanicLoop", PanicLoop)
42}
43
44func SimpleDeadlock() {
45	select {}
46	panic("not reached")
47}
48
49func InitDeadlock() {
50	select {}
51	panic("not reached")
52}
53
54func LockedDeadlock() {
55	runtime.LockOSThread()
56	select {}
57}
58
59func LockedDeadlock2() {
60	go func() {
61		runtime.LockOSThread()
62		select {}
63	}()
64	time.Sleep(time.Millisecond)
65	select {}
66}
67
68func GoexitDeadlock() {
69	F := func() {
70		for i := 0; i < 10; i++ {
71		}
72	}
73
74	go F()
75	go F()
76	runtime.Goexit()
77}
78
79func StackOverflow() {
80	var f func() byte
81	f = func() byte {
82		var buf [64 << 10]byte
83		return buf[0] + f()
84	}
85	debug.SetMaxStack(1474560)
86	f()
87}
88
89func ThreadExhaustion() {
90	debug.SetMaxThreads(10)
91	c := make(chan int)
92	for i := 0; i < 100; i++ {
93		go func() {
94			runtime.LockOSThread()
95			c <- 0
96			select {}
97		}()
98		<-c
99	}
100}
101
102func RecursivePanic() {
103	func() {
104		defer func() {
105			fmt.Println(recover())
106		}()
107		var x [8192]byte
108		func(x [8192]byte) {
109			defer func() {
110				if err := recover(); err != nil {
111					panic("wrap: " + err.(string))
112				}
113			}()
114			panic("bad")
115		}(x)
116	}()
117	panic("again")
118}
119
120// Same as RecursivePanic, but do the first recover and the second panic in
121// separate defers, and make sure they are executed in the correct order.
122func RecursivePanic2() {
123	func() {
124		defer func() {
125			fmt.Println(recover())
126		}()
127		var x [8192]byte
128		func(x [8192]byte) {
129			defer func() {
130				panic("second panic")
131			}()
132			defer func() {
133				fmt.Println(recover())
134			}()
135			panic("first panic")
136		}(x)
137	}()
138	panic("third panic")
139}
140
141// Make sure that the first panic finished as a panic, even though the second
142// panic was recovered
143func RecursivePanic3() {
144	defer func() {
145		defer func() {
146			recover()
147		}()
148		panic("second panic")
149	}()
150	panic("first panic")
151}
152
153// Test case where a single defer recovers one panic but starts another panic. If
154// the second panic is never recovered, then the recovered first panic will still
155// appear on the panic stack (labeled '[recovered]') and the runtime stack.
156func RecursivePanic4() {
157	defer func() {
158		recover()
159		panic("second panic")
160	}()
161	panic("first panic")
162}
163
164// Test case where we have an open-coded defer higher up the stack (in two), and
165// in the current function (three) we recover in a defer while we still have
166// another defer to be processed.
167func RecursivePanic5() {
168	one()
169	panic("third panic")
170}
171
172//go:noinline
173func one() {
174	two()
175}
176
177//go:noinline
178func two() {
179	defer func() {
180	}()
181
182	three()
183}
184
185//go:noinline
186func three() {
187	defer func() {
188	}()
189
190	defer func() {
191		fmt.Println(recover())
192	}()
193
194	defer func() {
195		fmt.Println(recover())
196		panic("second panic")
197	}()
198
199	panic("first panic")
200}
201
202func GoexitExit() {
203	println("t1")
204	go func() {
205		time.Sleep(time.Millisecond)
206	}()
207	i := 0
208	println("t2")
209	runtime.SetFinalizer(&i, func(p *int) {})
210	println("t3")
211	runtime.GC()
212	println("t4")
213	runtime.Goexit()
214}
215
216func GoNil() {
217	defer func() {
218		recover()
219	}()
220	var f func()
221	go f()
222	select {}
223}
224
225func MainGoroutineID() {
226	panic("test")
227}
228
229func NoHelperGoroutines() {
230	i := 0
231	runtime.SetFinalizer(&i, func(p *int) {})
232	time.AfterFunc(time.Hour, func() {})
233	panic("oops")
234}
235
236func Breakpoint() {
237	runtime.Breakpoint()
238}
239
240func GoexitInPanic() {
241	go func() {
242		defer func() {
243			runtime.Goexit()
244		}()
245		panic("hello")
246	}()
247	runtime.Goexit()
248}
249
250type errorThatGosched struct{}
251
252func (errorThatGosched) Error() string {
253	runtime.Gosched()
254	return "errorThatGosched"
255}
256
257func GoschedInPanic() {
258	panic(errorThatGosched{})
259}
260
261type errorThatPrint struct{}
262
263func (errorThatPrint) Error() string {
264	fmt.Println("1")
265	fmt.Println("2")
266	return "3"
267}
268
269func SyscallInPanic() {
270	panic(errorThatPrint{})
271}
272
273func PanicAfterGoexit() {
274	defer func() {
275		panic("hello")
276	}()
277	runtime.Goexit()
278}
279
280func RecoveredPanicAfterGoexit() {
281	defer func() {
282		defer func() {
283			r := recover()
284			if r == nil {
285				panic("bad recover")
286			}
287		}()
288		panic("hello")
289	}()
290	runtime.Goexit()
291}
292
293func RecoverBeforePanicAfterGoexit() {
294	// 1. defer a function that recovers
295	// 2. defer a function that panics
296	// 3. call goexit
297	// Goexit runs the #2 defer. Its panic
298	// is caught by the #1 defer.  For Goexit, we explicitly
299	// resume execution in the Goexit loop, instead of resuming
300	// execution in the caller (which would make the Goexit disappear!)
301	defer func() {
302		r := recover()
303		if r == nil {
304			panic("bad recover")
305		}
306	}()
307	defer func() {
308		panic("hello")
309	}()
310	runtime.Goexit()
311}
312
313func RecoverBeforePanicAfterGoexit2() {
314	for i := 0; i < 2; i++ {
315		defer func() {
316		}()
317	}
318	// 1. defer a function that recovers
319	// 2. defer a function that panics
320	// 3. call goexit
321	// Goexit runs the #2 defer. Its panic
322	// is caught by the #1 defer.  For Goexit, we explicitly
323	// resume execution in the Goexit loop, instead of resuming
324	// execution in the caller (which would make the Goexit disappear!)
325	defer func() {
326		r := recover()
327		if r == nil {
328			panic("bad recover")
329		}
330	}()
331	defer func() {
332		panic("hello")
333	}()
334	runtime.Goexit()
335}
336
337func PanicTraceback() {
338	pt1()
339}
340
341func pt1() {
342	defer func() {
343		panic("panic pt1")
344	}()
345	pt2()
346}
347
348func pt2() {
349	defer func() {
350		panic("panic pt2")
351	}()
352	panic("hello")
353}
354
355type panicError struct{}
356
357func (*panicError) Error() string {
358	panic("double error")
359}
360
361func PanicLoop() {
362	panic(&panicError{})
363}
364