...

Source file src/runtime/callers_test.go

Documentation: runtime

		 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  
		 5  package runtime_test
		 6  
		 7  import (
		 8  	"reflect"
		 9  	"runtime"
		10  	"strings"
		11  	"testing"
		12  )
		13  
		14  func f1(pan bool) []uintptr {
		15  	return f2(pan) // line 15
		16  }
		17  
		18  func f2(pan bool) []uintptr {
		19  	return f3(pan) // line 19
		20  }
		21  
		22  func 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  
		30  func 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  
		70  func 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  
		88  func TestCallers(t *testing.T) {
		89  	testCallers(t, f1(false), false)
		90  }
		91  
		92  func 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  
	 111  func 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.
	 136  func 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  
	 152  func 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  
	 184  func 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  
	 214  func 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  
	 235  func 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  
	 256  func 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
	 286  func 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  

View as plain text