github.com/x04/go/src@v0.0.0-20200202162449-3d481ceb3525/runtime/callers_test.go (about)

     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  	"github.com/x04/go/src/reflect"
     9  	"github.com/x04/go/src/runtime"
    10  	"github.com/x04/go/src/strings"
    11  	"github.com/x04/go/src/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  	got := make([]string, 0, len(want))
    72  
    73  	frames := runtime.CallersFrames(pcs)
    74  	for {
    75  		frame, more := frames.Next()
    76  		if !more || len(got) >= len(want) {
    77  			break
    78  		}
    79  		got = append(got, frame.Function)
    80  	}
    81  	if !reflect.DeepEqual(want, got) {
    82  		t.Fatalf("wanted %v, got %v", want, got)
    83  	}
    84  }
    85  
    86  func TestCallers(t *testing.T) {
    87  	testCallers(t, f1(false), false)
    88  }
    89  
    90  func TestCallersPanic(t *testing.T) {
    91  	// Make sure we don't have any extra frames on the stack (due to
    92  	// open-coded defer processing)
    93  	want := []string{"runtime.Callers", "runtime_test.TestCallersPanic.func1",
    94  		"runtime.gopanic", "runtime_test.f3", "runtime_test.f2", "runtime_test.f1",
    95  		"runtime_test.TestCallersPanic"}
    96  
    97  	defer func() {
    98  		if r := recover(); r == nil {
    99  			t.Fatal("did not panic")
   100  		}
   101  		pcs := make([]uintptr, 20)
   102  		pcs = pcs[:runtime.Callers(0, pcs)]
   103  		testCallers(t, pcs, true)
   104  		testCallersEqual(t, pcs, want)
   105  	}()
   106  	f1(true)
   107  }
   108  
   109  func TestCallersDoublePanic(t *testing.T) {
   110  	// Make sure we don't have any extra frames on the stack (due to
   111  	// open-coded defer processing)
   112  	want := []string{"runtime.Callers", "runtime_test.TestCallersDoublePanic.func1.1",
   113  		"runtime.gopanic", "runtime_test.TestCallersDoublePanic.func1", "runtime.gopanic", "runtime_test.TestCallersDoublePanic"}
   114  
   115  	defer func() {
   116  		defer func() {
   117  			pcs := make([]uintptr, 20)
   118  			pcs = pcs[:runtime.Callers(0, pcs)]
   119  			if recover() == nil {
   120  				t.Fatal("did not panic")
   121  			}
   122  			testCallersEqual(t, pcs, want)
   123  		}()
   124  		if recover() == nil {
   125  			t.Fatal("did not panic")
   126  		}
   127  		panic(2)
   128  	}()
   129  	panic(1)
   130  }
   131  
   132  // Test that a defer after a successful recovery looks like it is called directly
   133  // from the function with the defers.
   134  func TestCallersAfterRecovery(t *testing.T) {
   135  	want := []string{"runtime.Callers", "runtime_test.TestCallersAfterRecovery.func1", "runtime_test.TestCallersAfterRecovery"}
   136  
   137  	defer func() {
   138  		pcs := make([]uintptr, 20)
   139  		pcs = pcs[:runtime.Callers(0, pcs)]
   140  		testCallersEqual(t, pcs, want)
   141  	}()
   142  	defer func() {
   143  		if recover() == nil {
   144  			t.Fatal("did not recover from panic")
   145  		}
   146  	}()
   147  	panic(1)
   148  }
   149  
   150  func TestCallersAbortedPanic(t *testing.T) {
   151  	want := []string{"runtime.Callers", "runtime_test.TestCallersAbortedPanic.func2", "runtime_test.TestCallersAbortedPanic"}
   152  
   153  	defer func() {
   154  		r := recover()
   155  		if r != nil {
   156  			t.Fatalf("should be no panic remaining to recover")
   157  		}
   158  	}()
   159  
   160  	defer func() {
   161  		// panic2 was aborted/replaced by panic1, so when panic2 was
   162  		// recovered, there is no remaining panic on the stack.
   163  		pcs := make([]uintptr, 20)
   164  		pcs = pcs[:runtime.Callers(0, pcs)]
   165  		testCallersEqual(t, pcs, want)
   166  	}()
   167  	defer func() {
   168  		r := recover()
   169  		if r != "panic2" {
   170  			t.Fatalf("got %v, wanted %v", r, "panic2")
   171  		}
   172  	}()
   173  	defer func() {
   174  		// panic2 aborts/replaces panic1, because it is a recursive panic
   175  		// that is not recovered within the defer function called by
   176  		// panic1 panicking sequence
   177  		panic("panic2")
   178  	}()
   179  	panic("panic1")
   180  }
   181  
   182  func TestCallersAbortedPanic2(t *testing.T) {
   183  	want := []string{"runtime.Callers", "runtime_test.TestCallersAbortedPanic2.func2", "runtime_test.TestCallersAbortedPanic2"}
   184  	defer func() {
   185  		r := recover()
   186  		if r != nil {
   187  			t.Fatalf("should be no panic remaining to recover")
   188  		}
   189  	}()
   190  	defer func() {
   191  		pcs := make([]uintptr, 20)
   192  		pcs = pcs[:runtime.Callers(0, pcs)]
   193  		testCallersEqual(t, pcs, want)
   194  	}()
   195  	func() {
   196  		defer func() {
   197  			r := recover()
   198  			if r != "panic2" {
   199  				t.Fatalf("got %v, wanted %v", r, "panic2")
   200  			}
   201  		}()
   202  		func() {
   203  			defer func() {
   204  				// Again, panic2 aborts/replaces panic1
   205  				panic("panic2")
   206  			}()
   207  			panic("panic1")
   208  		}()
   209  	}()
   210  }
   211  
   212  func TestCallersNilPointerPanic(t *testing.T) {
   213  	// Make sure we don't have any extra frames on the stack (due to
   214  	// open-coded defer processing)
   215  	want := []string{"runtime.Callers", "runtime_test.TestCallersNilPointerPanic.func1",
   216  		"runtime.gopanic", "runtime.panicmem", "runtime.sigpanic",
   217  		"runtime_test.TestCallersNilPointerPanic"}
   218  
   219  	defer func() {
   220  		if r := recover(); r == nil {
   221  			t.Fatal("did not panic")
   222  		}
   223  		pcs := make([]uintptr, 20)
   224  		pcs = pcs[:runtime.Callers(0, pcs)]
   225  		testCallersEqual(t, pcs, want)
   226  	}()
   227  	var p *int
   228  	if *p == 3 {
   229  		t.Fatal("did not see nil pointer panic")
   230  	}
   231  }
   232  
   233  func TestCallersDivZeroPanic(t *testing.T) {
   234  	// Make sure we don't have any extra frames on the stack (due to
   235  	// open-coded defer processing)
   236  	want := []string{"runtime.Callers", "runtime_test.TestCallersDivZeroPanic.func1",
   237  		"runtime.gopanic", "runtime.panicdivide",
   238  		"runtime_test.TestCallersDivZeroPanic"}
   239  
   240  	defer func() {
   241  		if r := recover(); r == nil {
   242  			t.Fatal("did not panic")
   243  		}
   244  		pcs := make([]uintptr, 20)
   245  		pcs = pcs[:runtime.Callers(0, pcs)]
   246  		testCallersEqual(t, pcs, want)
   247  	}()
   248  	var n int
   249  	if 5/n == 1 {
   250  		t.Fatal("did not see divide-by-sizer panic")
   251  	}
   252  }
   253  
   254  func TestCallersDeferNilFuncPanic(t *testing.T) {
   255  	// Make sure we don't have any extra frames on the stack. We cut off the check
   256  	// at runtime.sigpanic, because non-open-coded defers (which may be used in
   257  	// non-opt or race checker mode) include an extra 'deferreturn' frame (which is
   258  	// where the nil pointer deref happens).
   259  	state := 1
   260  	want := []string{"runtime.Callers", "runtime_test.TestCallersDeferNilFuncPanic.func1",
   261  		"runtime.gopanic", "runtime.panicmem", "runtime.sigpanic"}
   262  
   263  	defer func() {
   264  		if r := recover(); r == nil {
   265  			t.Fatal("did not panic")
   266  		}
   267  		pcs := make([]uintptr, 20)
   268  		pcs = pcs[:runtime.Callers(0, pcs)]
   269  		testCallersEqual(t, pcs, want)
   270  		if state == 1 {
   271  			t.Fatal("nil defer func panicked at defer time rather than function exit time")
   272  		}
   273  
   274  	}()
   275  	var f func()
   276  	defer f()
   277  	// Use the value of 'state' to make sure nil defer func f causes panic at
   278  	// function exit, rather than at the defer statement.
   279  	state = 2
   280  }
   281  
   282  // Same test, but forcing non-open-coded defer by putting the defer in a loop.  See
   283  // issue #36050
   284  func TestCallersDeferNilFuncPanicWithLoop(t *testing.T) {
   285  	state := 1
   286  	want := []string{"runtime.Callers", "runtime_test.TestCallersDeferNilFuncPanicWithLoop.func1",
   287  		"runtime.gopanic", "runtime.panicmem", "runtime.sigpanic", "runtime.deferreturn", "runtime_test.TestCallersDeferNilFuncPanicWithLoop"}
   288  
   289  	defer func() {
   290  		if r := recover(); r == nil {
   291  			t.Fatal("did not panic")
   292  		}
   293  		pcs := make([]uintptr, 20)
   294  		pcs = pcs[:runtime.Callers(0, pcs)]
   295  		testCallersEqual(t, pcs, want)
   296  		if state == 1 {
   297  			t.Fatal("nil defer func panicked at defer time rather than function exit time")
   298  		}
   299  
   300  	}()
   301  
   302  	for i := 0; i < 1; i++ {
   303  		var f func()
   304  		defer f()
   305  	}
   306  	// Use the value of 'state' to make sure nil defer func f causes panic at
   307  	// function exit, rather than at the defer statement.
   308  	state = 2
   309  }