mirror of
https://github.com/golang/go
synced 2024-11-25 13:47:57 -07:00
a51e4cc9ce
Move the zeroing of results earlier. In particular, they need to come before any move-to-heap operations, as those require allocation. Those allocations are points at which the GC can see the uninitialized result slots. For the function: func f() (x, y, z *int) { defer(){}() escape(&y) return } We used to generate code like this: x = nil y = nil &y = new(int) z = nil Now we will generate: x = nil y = nil z = nil &y = new(int) Since the fix for #18860, the return slots are always live if there is a defer, so the former ordering allowed the GC to see junk in the z slot. Fixes #19078 Change-Id: I71554ae437549725bb79e13b2c100b2911d47ed4 Reviewed-on: https://go-review.googlesource.com/38133 Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
43 lines
1.2 KiB
Go
43 lines
1.2 KiB
Go
// run
|
|
|
|
// Copyright 2017 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.
|
|
|
|
// Issue 19078: liveness & zero-initialization of results
|
|
// when there is a defer.
|
|
package main
|
|
|
|
import "unsafe"
|
|
|
|
func main() {
|
|
// Construct an invalid pointer. We do this by
|
|
// making a pointer which points to the unused space
|
|
// between the last 48-byte object in a span and the
|
|
// end of the span (there are 32 unused bytes there).
|
|
p := new([48]byte) // make a 48-byte object
|
|
sink = &p // escape it, so it allocates for real
|
|
u := uintptr(unsafe.Pointer(p)) // get its address
|
|
u = u >> 13 << 13 // round down to page size
|
|
u += 1<<13 - 1 // add almost a page
|
|
|
|
for i := 0; i < 1000000; i++ {
|
|
_ = identity(u) // installs u at return slot
|
|
_ = liveReturnSlot(nil) // incorrectly marks return slot as live
|
|
}
|
|
}
|
|
|
|
//go:noinline
|
|
func liveReturnSlot(x *int) *int {
|
|
defer func() {}() // causes return slot to be marked live
|
|
sink = &x // causes x to be moved to the heap, triggering allocation
|
|
return x
|
|
}
|
|
|
|
//go:noinline
|
|
func identity(x uintptr) uintptr {
|
|
return x
|
|
}
|
|
|
|
var sink interface{}
|