LEFT | RIGHT |
1 // Copyright 2012 The Go Authors. All rights reserved. | 1 // Copyright 2012 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package runtime_test | 5 package runtime_test |
6 | 6 |
7 import ( | 7 import ( |
8 . "runtime" | 8 . "runtime" |
9 "strings" | 9 "strings" |
10 "sync" | 10 "sync" |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 | 223 |
224 defer func() { | 224 defer func() { |
225 if y != 42 { | 225 if y != 42 { |
226 t.Errorf("defer's stack references were not adjusted app
ropriately") | 226 t.Errorf("defer's stack references were not adjusted app
ropriately") |
227 } | 227 } |
228 }() | 228 }() |
229 defer set(&y, 42) | 229 defer set(&y, 42) |
230 growStack() | 230 growStack() |
231 } | 231 } |
232 | 232 |
| 233 type bigBuf [4 * 1024]byte |
| 234 |
| 235 // TestDeferPtrsGoexit is like TestDeferPtrs but exercises the possibility that
the |
| 236 // stack grows as part of starting the deferred function. It calls Goexit at var
ious |
| 237 // stack depths, forcing the deferred function (with >4kB of args) to be run at |
| 238 // the bottom of the stack. The goal is to find a stack depth less than 4kB from |
| 239 // the end of the stack. Each trial runs in a different goroutine so that an ear
lier |
| 240 // stack growth does not invalidate a later attempt. |
| 241 func TestDeferPtrsGoexit(t *testing.T) { |
| 242 for i := 0; i < 100; i++ { |
| 243 c := make(chan int, 1) |
| 244 go testDeferPtrsGoexit(c, i) |
| 245 if n := <-c; n != 42 { |
| 246 t.Fatalf("defer's stack references were not adjusted app
ropriately (i=%d n=%d)", i, n) |
| 247 } |
| 248 } |
| 249 } |
| 250 |
| 251 func testDeferPtrsGoexit(c chan int, i int) { |
| 252 var y int |
| 253 defer func() { |
| 254 c <- y |
| 255 }() |
| 256 defer setBig(&y, 42, bigBuf{}) |
| 257 useStackAndCall(i, Goexit) |
| 258 } |
| 259 |
| 260 func setBig(p *int, x int, b bigBuf) { |
| 261 *p = x |
| 262 } |
| 263 |
| 264 // TestDeferPtrsPanic is like TestDeferPtrsGoexit, but it's using panic instead |
| 265 // of Goexit to run the Defers. Those two are different execution paths |
| 266 // in the runtime. |
| 267 func TestDeferPtrsPanic(t *testing.T) { |
| 268 for i := 0; i < 100; i++ { |
| 269 c := make(chan int, 1) |
| 270 go testDeferPtrsGoexit(c, i) |
| 271 if n := <-c; n != 42 { |
| 272 t.Fatalf("defer's stack references were not adjusted app
ropriately (i=%d n=%d)", i, n) |
| 273 } |
| 274 } |
| 275 } |
| 276 |
| 277 func testDeferPtrsPanic(c chan int, i int) { |
| 278 var y int |
| 279 defer func() { |
| 280 if recover() == nil { |
| 281 c <- -1 |
| 282 return |
| 283 } |
| 284 c <- y |
| 285 }() |
| 286 defer setBig(&y, 42, bigBuf{}) |
| 287 useStackAndCall(i, func() { panic(1) }) |
| 288 } |
| 289 |
| 290 // TestPanicUseStack checks that a chain of Panic structs on the stack are |
| 291 // updated correctly if the stack grows during the deferred execution that |
| 292 // happens as a result of the panic. |
233 func TestPanicUseStack(t *testing.T) { | 293 func TestPanicUseStack(t *testing.T) { |
234 pc := make([]uintptr, 10000) | 294 pc := make([]uintptr, 10000) |
235 defer func() { | 295 defer func() { |
236 recover() | 296 recover() |
237 Callers(0, pc) // force stack walk | 297 Callers(0, pc) // force stack walk |
238 useStackAndCall(100, func() { | 298 useStackAndCall(100, func() { |
239 defer func() { | 299 defer func() { |
240 recover() | 300 recover() |
241 Callers(0, pc) // force stack walk | 301 Callers(0, pc) // force stack walk |
242 useStackAndCall(200, func() { | 302 useStackAndCall(200, func() { |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
332 // To make this test effective, edit panic.go:gopanic and uncomment | 392 // To make this test effective, edit panic.go:gopanic and uncomment |
333 // the GC() call just before freedefer(d). | 393 // the GC() call just before freedefer(d). |
334 defer func() { | 394 defer func() { |
335 if x := recover(); x == nil { | 395 if x := recover(); x == nil { |
336 t.Errorf("recover failed") | 396 t.Errorf("recover failed") |
337 } | 397 } |
338 }() | 398 }() |
339 useStack(32) | 399 useStack(32) |
340 panic("test panic") | 400 panic("test panic") |
341 } | 401 } |
LEFT | RIGHT |