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 }