1// Copyright 2016 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	"strings"
11	"testing"
12)
13
14func f1(pan bool) []uintptr {
15	return f2(pan) // line 15
16}
17
18func f2(pan bool) []uintptr {
19	return f3(pan) // line 19
20}
21
22func f3(pan bool) []uintptr {
23	if pan {
24		panic("f3") // line 24
25	}
26	ret := make([]uintptr, 20)
27	return ret[:runtime.Callers(0, ret)] // line 27
28}
29
30func testCallers(t *testing.T, pcs []uintptr, pan bool) {
31	m := make(map[string]int, len(pcs))
32	frames := runtime.CallersFrames(pcs)
33	for {
34		frame, more := frames.Next()
35		if frame.Function != "" {
36			m[frame.Function] = frame.Line
37		}
38		if !more {
39			break
40		}
41	}
42
43	var seen []string
44	for k := range m {
45		seen = append(seen, k)
46	}
47	t.Logf("functions seen: %s", strings.Join(seen, " "))
48
49	var f3Line int
50	if pan {
51		f3Line = 24
52	} else {
53		f3Line = 27
54	}
55	want := []struct {
56		name string
57		line int
58	}{
59		{"f1", 15},
60		{"f2", 19},
61		{"f3", f3Line},
62	}
63	for _, w := range want {
64		if got := m["runtime_test."+w.name]; got != w.line {
65			t.Errorf("%s is line %d, want %d", w.name, got, w.line)
66		}
67	}
68}
69
70func testCallersEqual(t *testing.T, pcs []uintptr, want []string) {
71	t.Helper()
72
73	got := make([]string, 0, len(want))
74
75	frames := runtime.CallersFrames(pcs)
76	for {
77		frame, more := frames.Next()
78		if !more || len(got) >= len(want) {
79			break
80		}
81		got = append(got, frame.Function)
82	}
83	if !reflect.DeepEqual(want, got) {
84		t.Fatalf("wanted %v, got %v", want, got)
85	}
86}
87
88func TestCallers(t *testing.T) {
89	testCallers(t, f1(false), false)
90}
91
92func TestCallersPanic(t *testing.T) {
93	// Make sure we don't have any extra frames on the stack (due to
94	// open-coded defer processing)
95	want := []string{"runtime.Callers", "runtime_test.TestCallersPanic.func1",
96		"runtime.gopanic", "runtime_test.f3", "runtime_test.f2", "runtime_test.f1",
97		"runtime_test.TestCallersPanic"}
98
99	defer func() {
100		if r := recover(); r == nil {
101			t.Fatal("did not panic")
102		}
103		pcs := make([]uintptr, 20)
104		pcs = pcs[:runtime.Callers(0, pcs)]
105		testCallers(t, pcs, true)
106		testCallersEqual(t, pcs, want)
107	}()
108	f1(true)
109}
110
111func TestCallersDoublePanic(t *testing.T) {
112	// Make sure we don't have any extra frames on the stack (due to
113	// open-coded defer processing)
114	want := []string{"runtime.Callers", "runtime_test.TestCallersDoublePanic.func1.1",
115		"runtime.gopanic", "runtime_test.TestCallersDoublePanic.func1", "runtime.gopanic", "runtime_test.TestCallersDoublePanic"}
116
117	defer func() {
118		defer func() {
119			pcs := make([]uintptr, 20)
120			pcs = pcs[:runtime.Callers(0, pcs)]
121			if recover() == nil {
122				t.Fatal("did not panic")
123			}
124			testCallersEqual(t, pcs, want)
125		}()
126		if recover() == nil {
127			t.Fatal("did not panic")
128		}
129		panic(2)
130	}()
131	panic(1)
132}
133
134// Test that a defer after a successful recovery looks like it is called directly
135// from the function with the defers.
136func TestCallersAfterRecovery(t *testing.T) {
137	want := []string{"runtime.Callers", "runtime_test.TestCallersAfterRecovery.func1", "runtime_test.TestCallersAfterRecovery"}
138
139	defer func() {
140		pcs := make([]uintptr, 20)
141		pcs = pcs[:runtime.Callers(0, pcs)]
142		testCallersEqual(t, pcs, want)
143	}()
144	defer func() {
145		if recover() == nil {
146			t.Fatal("did not recover from panic")
147		}
148	}()
149	panic(1)
150}
151
152func TestCallersAbortedPanic(t *testing.T) {
153	want := []string{"runtime.Callers", "runtime_test.TestCallersAbortedPanic.func2", "runtime_test.TestCallersAbortedPanic"}
154
155	defer func() {
156		r := recover()
157		if r != nil {
158			t.Fatalf("should be no panic remaining to recover")
159		}
160	}()
161
162	defer func() {
163		// panic2 was aborted/replaced by panic1, so when panic2 was
164		// recovered, there is no remaining panic on the stack.
165		pcs := make([]uintptr, 20)
166		pcs = pcs[:runtime.Callers(0, pcs)]
167		testCallersEqual(t, pcs, want)
168	}()
169	defer func() {
170		r := recover()
171		if r != "panic2" {
172			t.Fatalf("got %v, wanted %v", r, "panic2")
173		}
174	}()
175	defer func() {
176		// panic2 aborts/replaces panic1, because it is a recursive panic
177		// that is not recovered within the defer function called by
178		// panic1 panicking sequence
179		panic("panic2")
180	}()
181	panic("panic1")
182}
183
184func TestCallersAbortedPanic2(t *testing.T) {
185	want := []string{"runtime.Callers", "runtime_test.TestCallersAbortedPanic2.func2", "runtime_test.TestCallersAbortedPanic2"}
186	defer func() {
187		r := recover()
188		if r != nil {
189			t.Fatalf("should be no panic remaining to recover")
190		}
191	}()
192	defer func() {
193		pcs := make([]uintptr, 20)
194		pcs = pcs[:runtime.Callers(0, pcs)]
195		testCallersEqual(t, pcs, want)
196	}()
197	func() {
198		defer func() {
199			r := recover()
200			if r != "panic2" {
201				t.Fatalf("got %v, wanted %v", r, "panic2")
202			}
203		}()
204		func() {
205			defer func() {
206				// Again, panic2 aborts/replaces panic1
207				panic("panic2")
208			}()
209			panic("panic1")
210		}()
211	}()
212}
213
214func TestCallersNilPointerPanic(t *testing.T) {
215	// Make sure we don't have any extra frames on the stack (due to
216	// open-coded defer processing)
217	want := []string{"runtime.Callers", "runtime_test.TestCallersNilPointerPanic.func1",
218		"runtime.gopanic", "runtime.panicmem", "runtime.sigpanic",
219		"runtime_test.TestCallersNilPointerPanic"}
220
221	defer func() {
222		if r := recover(); r == nil {
223			t.Fatal("did not panic")
224		}
225		pcs := make([]uintptr, 20)
226		pcs = pcs[:runtime.Callers(0, pcs)]
227		testCallersEqual(t, pcs, want)
228	}()
229	var p *int
230	if *p == 3 {
231		t.Fatal("did not see nil pointer panic")
232	}
233}
234
235func TestCallersDivZeroPanic(t *testing.T) {
236	// Make sure we don't have any extra frames on the stack (due to
237	// open-coded defer processing)
238	want := []string{"runtime.Callers", "runtime_test.TestCallersDivZeroPanic.func1",
239		"runtime.gopanic", "runtime.panicdivide",
240		"runtime_test.TestCallersDivZeroPanic"}
241
242	defer func() {
243		if r := recover(); r == nil {
244			t.Fatal("did not panic")
245		}
246		pcs := make([]uintptr, 20)
247		pcs = pcs[:runtime.Callers(0, pcs)]
248		testCallersEqual(t, pcs, want)
249	}()
250	var n int
251	if 5/n == 1 {
252		t.Fatal("did not see divide-by-sizer panic")
253	}
254}
255
256func TestCallersDeferNilFuncPanic(t *testing.T) {
257	// Make sure we don't have any extra frames on the stack. We cut off the check
258	// at runtime.sigpanic, because non-open-coded defers (which may be used in
259	// non-opt or race checker mode) include an extra 'deferreturn' frame (which is
260	// where the nil pointer deref happens).
261	state := 1
262	want := []string{"runtime.Callers", "runtime_test.TestCallersDeferNilFuncPanic.func1",
263		"runtime.gopanic", "runtime.panicmem", "runtime.sigpanic"}
264
265	defer func() {
266		if r := recover(); r == nil {
267			t.Fatal("did not panic")
268		}
269		pcs := make([]uintptr, 20)
270		pcs = pcs[:runtime.Callers(0, pcs)]
271		testCallersEqual(t, pcs, want)
272		if state == 1 {
273			t.Fatal("nil defer func panicked at defer time rather than function exit time")
274		}
275
276	}()
277	var f func()
278	defer f()
279	// Use the value of 'state' to make sure nil defer func f causes panic at
280	// function exit, rather than at the defer statement.
281	state = 2
282}
283
284// Same test, but forcing non-open-coded defer by putting the defer in a loop.  See
285// issue #36050
286func TestCallersDeferNilFuncPanicWithLoop(t *testing.T) {
287	state := 1
288	want := []string{"runtime.Callers", "runtime_test.TestCallersDeferNilFuncPanicWithLoop.func1",
289		"runtime.gopanic", "runtime.panicmem", "runtime.sigpanic", "runtime.deferreturn", "runtime_test.TestCallersDeferNilFuncPanicWithLoop"}
290
291	defer func() {
292		if r := recover(); r == nil {
293			t.Fatal("did not panic")
294		}
295		pcs := make([]uintptr, 20)
296		pcs = pcs[:runtime.Callers(0, pcs)]
297		testCallersEqual(t, pcs, want)
298		if state == 1 {
299			t.Fatal("nil defer func panicked at defer time rather than function exit time")
300		}
301
302	}()
303
304	for i := 0; i < 1; i++ {
305		var f func()
306		defer f()
307	}
308	// Use the value of 'state' to make sure nil defer func f causes panic at
309	// function exit, rather than at the defer statement.
310	state = 2
311}
312
313// issue #51988
314// Func.Endlineno was lost when instantiating generic functions, leading to incorrect
315// stack trace positions.
316func TestCallersEndlineno(t *testing.T) {
317	testNormalEndlineno(t)
318	testGenericEndlineno[int](t)
319}
320
321func testNormalEndlineno(t *testing.T) {
322	defer testCallerLine(t, callerLine(t, 0)+1)
323}
324
325func testGenericEndlineno[_ any](t *testing.T) {
326	defer testCallerLine(t, callerLine(t, 0)+1)
327}
328
329func testCallerLine(t *testing.T, want int) {
330	if have := callerLine(t, 1); have != want {
331		t.Errorf("callerLine(1) returned %d, but want %d\n", have, want)
332	}
333}
334
335func callerLine(t *testing.T, skip int) int {
336	_, _, line, ok := runtime.Caller(skip + 1)
337	if !ok {
338		t.Fatalf("runtime.Caller(%d) failed", skip+1)
339	}
340	return line
341}
342
343func BenchmarkCallers(b *testing.B) {
344	b.Run("cached", func(b *testing.B) {
345		// Very pcvalueCache-friendly, no inlining.
346		callersCached(b, 100)
347	})
348	b.Run("inlined", func(b *testing.B) {
349		// Some inlining, still pretty cache-friendly.
350		callersInlined(b, 100)
351	})
352	b.Run("no-cache", func(b *testing.B) {
353		// Cache-hostile
354		callersNoCache(b, 100)
355	})
356}
357
358func callersCached(b *testing.B, n int) int {
359	if n <= 0 {
360		pcs := make([]uintptr, 32)
361		b.ResetTimer()
362		for i := 0; i < b.N; i++ {
363			runtime.Callers(0, pcs)
364		}
365		b.StopTimer()
366		return 0
367	}
368	return 1 + callersCached(b, n-1)
369}
370
371func callersInlined(b *testing.B, n int) int {
372	if n <= 0 {
373		pcs := make([]uintptr, 32)
374		b.ResetTimer()
375		for i := 0; i < b.N; i++ {
376			runtime.Callers(0, pcs)
377		}
378		b.StopTimer()
379		return 0
380	}
381	return 1 + callersInlined1(b, n-1)
382}
383func callersInlined1(b *testing.B, n int) int { return callersInlined2(b, n) }
384func callersInlined2(b *testing.B, n int) int { return callersInlined3(b, n) }
385func callersInlined3(b *testing.B, n int) int { return callersInlined4(b, n) }
386func callersInlined4(b *testing.B, n int) int { return callersInlined(b, n) }
387
388func callersNoCache(b *testing.B, n int) int {
389	if n <= 0 {
390		pcs := make([]uintptr, 32)
391		b.ResetTimer()
392		for i := 0; i < b.N; i++ {
393			runtime.Callers(0, pcs)
394		}
395		b.StopTimer()
396		return 0
397	}
398	switch n % 16 {
399	case 0:
400		return 1 + callersNoCache(b, n-1)
401	case 1:
402		return 1 + callersNoCache(b, n-1)
403	case 2:
404		return 1 + callersNoCache(b, n-1)
405	case 3:
406		return 1 + callersNoCache(b, n-1)
407	case 4:
408		return 1 + callersNoCache(b, n-1)
409	case 5:
410		return 1 + callersNoCache(b, n-1)
411	case 6:
412		return 1 + callersNoCache(b, n-1)
413	case 7:
414		return 1 + callersNoCache(b, n-1)
415	case 8:
416		return 1 + callersNoCache(b, n-1)
417	case 9:
418		return 1 + callersNoCache(b, n-1)
419	case 10:
420		return 1 + callersNoCache(b, n-1)
421	case 11:
422		return 1 + callersNoCache(b, n-1)
423	case 12:
424		return 1 + callersNoCache(b, n-1)
425	case 13:
426		return 1 + callersNoCache(b, n-1)
427	case 14:
428		return 1 + callersNoCache(b, n-1)
429	default:
430		return 1 + callersNoCache(b, n-1)
431	}
432}
433
434func BenchmarkFPCallers(b *testing.B) {
435	b.Run("cached", func(b *testing.B) {
436		// Very pcvalueCache-friendly, no inlining.
437		fpCallersCached(b, 100)
438	})
439}
440
441func fpCallersCached(b *testing.B, n int) int {
442	if n <= 0 {
443		pcs := make([]uintptr, 32)
444		b.ResetTimer()
445		for i := 0; i < b.N; i++ {
446			runtime.FPCallers(pcs)
447		}
448		b.StopTimer()
449		return 0
450	}
451	return 1 + fpCallersCached(b, n-1)
452}
453
454func TestFPUnwindAfterRecovery(t *testing.T) {
455	if !runtime.FramePointerEnabled {
456		t.Skip("frame pointers not supported for this architecture")
457	}
458	// Make sure that frame pointer unwinding succeeds from a deferred
459	// function run after recovering from a panic. It can fail if the
460	// recovery does not properly restore the caller's frame pointer before
461	// running the remaining deferred functions.
462	//
463	// This test does not verify the accuracy of the call stack (it
464	// currently includes a frame from runtime.deferreturn which would
465	// normally be omitted). It is only intended to check that producing the
466	// call stack won't crash.
467	defer func() {
468		pcs := make([]uintptr, 32)
469		for i := range pcs {
470			// If runtime.recovery doesn't properly restore the
471			// frame pointer before returning control to this
472			// function, it will point somewhere lower in the stack
473			// from one of the frames of runtime.gopanic() or one of
474			// it's callees prior to recovery.  So, we put some
475			// non-zero values on the stack to ensure that frame
476			// pointer unwinding will crash if it sees the old,
477			// invalid frame pointer.
478			pcs[i] = 10
479		}
480		runtime.FPCallers(pcs)
481		t.Logf("%v", pcs)
482	}()
483	defer func() {
484		if recover() == nil {
485			t.Fatal("did not recover from panic")
486		}
487	}()
488	panic(1)
489}
490