LEFT | RIGHT |
(no file at all) | |
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 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
134 for i := 0; i < n; i++ { | 134 for i := 0; i < n; i++ { |
135 x := 0 | 135 x := 0 |
136 growStackIter(&x, i) | 136 growStackIter(&x, i) |
137 if x != i+1 { | 137 if x != i+1 { |
138 panic("stack is corrupted") | 138 panic("stack is corrupted") |
139 } | 139 } |
140 } | 140 } |
141 GC() | 141 GC() |
142 } | 142 } |
143 | 143 |
144 // This function is not an anonimous func, so that the compiler can do escape | 144 // This function is not an anonymous func, so that the compiler can do escape |
145 // analysis and place x on stack (and subsequently stack growth update the point
er). | 145 // analysis and place x on stack (and subsequently stack growth update the point
er). |
146 func growStackIter(p *int, n int) { | 146 func growStackIter(p *int, n int) { |
147 if n == 0 { | 147 if n == 0 { |
148 *p = n + 1 | 148 *p = n + 1 |
149 GC() | 149 GC() |
150 return | 150 return |
151 } | 151 } |
152 *p = n + 1 | 152 *p = n + 1 |
153 x := 0 | 153 x := 0 |
154 growStackIter(&x, n-1) | 154 growStackIter(&x, n-1) |
(...skipping 68 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 // use about n KB of stack | 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. |
| 293 func TestPanicUseStack(t *testing.T) { |
| 294 » pc := make([]uintptr, 10000) |
| 295 » defer func() { |
| 296 » » recover() |
| 297 » » Callers(0, pc) // force stack walk |
| 298 » » useStackAndCall(100, func() { |
| 299 » » » defer func() { |
| 300 » » » » recover() |
| 301 » » » » Callers(0, pc) // force stack walk |
| 302 » » » » useStackAndCall(200, func() { |
| 303 » » » » » defer func() { |
| 304 » » » » » » recover() |
| 305 » » » » » » Callers(0, pc) // force stack wa
lk |
| 306 » » » » » }() |
| 307 » » » » » panic(3) |
| 308 » » » » }) |
| 309 » » » }() |
| 310 » » » panic(2) |
| 311 » » }) |
| 312 » }() |
| 313 » panic(1) |
| 314 } |
| 315 |
| 316 // use about n KB of stack and call f |
| 317 func useStackAndCall(n int, f func()) { |
| 318 » if n == 0 { |
| 319 » » f() |
| 320 » » return |
| 321 » } |
| 322 » var b [1024]byte // makes frame about 1KB |
| 323 » useStackAndCall(n-1+int(b[99]), f) |
| 324 } |
| 325 |
234 func useStack(n int) { | 326 func useStack(n int) { |
235 » if n == 0 { | 327 » useStackAndCall(n, func() {}) |
236 » » return | |
237 » } | |
238 » var b [1024]byte // makes frame about 1KB | |
239 » useStack(n - 1 + int(b[99])) | |
240 } | 328 } |
241 | 329 |
242 func growing(c chan int, done chan struct{}) { | 330 func growing(c chan int, done chan struct{}) { |
243 for n := range c { | 331 for n := range c { |
244 useStack(n) | 332 useStack(n) |
245 done <- struct{}{} | 333 done <- struct{}{} |
246 } | 334 } |
247 done <- struct{}{} | 335 done <- struct{}{} |
248 } | 336 } |
249 | 337 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
304 // To make this test effective, edit panic.go:gopanic and uncomment | 392 // To make this test effective, edit panic.go:gopanic and uncomment |
305 // the GC() call just before freedefer(d). | 393 // the GC() call just before freedefer(d). |
306 defer func() { | 394 defer func() { |
307 if x := recover(); x == nil { | 395 if x := recover(); x == nil { |
308 t.Errorf("recover failed") | 396 t.Errorf("recover failed") |
309 } | 397 } |
310 }() | 398 }() |
311 useStack(32) | 399 useStack(32) |
312 panic("test panic") | 400 panic("test panic") |
313 } | 401 } |
LEFT | RIGHT |