| // run |
| |
| // Copyright 2018 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 ( |
| "runtime" |
| ) |
| |
| var nilp *int |
| var forceHeap interface{} |
| |
| func main() { |
| // x is a pointer on the stack to heap-allocated memory. |
| x := new([32]*int) |
| forceHeap = x |
| forceHeap = nil |
| |
| // Push a defer to be run when we panic below. |
| defer func() { |
| // Ignore the panic. |
| recover() |
| // Force a stack walk. Go 1.11 will fail because x is now |
| // considered live again. |
| runtime.GC() |
| }() |
| // Make x live at the defer's PC. |
| runtime.KeepAlive(x) |
| |
| // x is no longer live. Garbage collect the [32]*int on the |
| // heap. |
| runtime.GC() |
| // At this point x's dead stack slot points to dead memory. |
| |
| // Trigger a sigpanic. Since this is an implicit panic, we |
| // don't have an explicit liveness map here. |
| // Traceback used to use the liveness map of the most recent defer, |
| // but in that liveness map, x will be live again even though |
| // it points to dead memory. The fix is to use the liveness |
| // map of a deferreturn call instead. |
| *nilp = 0 |
| } |