| // run |
| |
| // Copyright 2020 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package main |
| |
| import "fmt" |
| |
| const N = 40 |
| |
| func main() { |
| var x [N]int // stack-allocated memory |
| for i := range x { |
| x[i] = 0x999 |
| } |
| |
| // This defer checks to see if x is uncorrupted. |
| defer func(p *[N]int) { |
| recover() |
| for i := range p { |
| if p[i] != 0x999 { |
| for j := range p { |
| fmt.Printf("p[%d]=0x%x\n", j, p[j]) |
| } |
| panic("corrupted stack variable") |
| } |
| } |
| }(&x) |
| |
| // This defer starts a new goroutine, which will (hopefully) |
| // overwrite x on the garbage stack. |
| defer func() { |
| c := make(chan bool) |
| go func() { |
| useStack(1000) |
| c <- true |
| }() |
| <-c |
| |
| }() |
| |
| // This defer causes a stack copy. |
| // The old stack is now garbage. |
| defer func() { |
| useStack(1000) |
| }() |
| |
| // Trigger a segfault. |
| *g = 0 |
| |
| // Make the return statement unreachable. |
| // That makes the stack map at the deferreturn call empty. |
| // In particular, the argument to the first defer is not |
| // marked as a pointer, so it doesn't get adjusted |
| // during the stack copy. |
| for { |
| } |
| } |
| |
| var g *int64 |
| |
| func useStack(n int) { |
| if n == 0 { |
| return |
| } |
| useStack(n - 1) |
| } |