|  | // 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) | 
|  | } |