mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: fix possible spill of invalid pointer with DUFFZERO on AMD64
SSA compiler on AMD64 may spill Duff-adjusted address as scalar. If the object is on stack and the stack moves, the spilled address become invalid. Making the spill pointer-typed does not work. The Duff-adjusted address points to the memory before the area to be zeroed and may be invalid. This may cause stack scanning code panic. Fix it by doing Duff-adjustment in genValue, so the intermediate value is not seen by the reg allocator, and will not be spilled. Add a test to cover both cases. As it depends on allocation, it may be not always triggered. Fixes #16515. Change-Id: Ia81d60204782de7405b7046165ad063384ede0db Reviewed-on: https://go-review.googlesource.com/25309 Run-TryBot: Cherry Zhang <cherryyz@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
be91515907
commit
111d590f86
6 changed files with 103 additions and 59 deletions
|
|
@ -254,52 +254,6 @@ func isSamePtr(p1, p2 *Value) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// DUFFZERO consists of repeated blocks of 4 MOVUPSs + ADD,
|
||||
// See runtime/mkduff.go.
|
||||
const (
|
||||
dzBlocks = 16 // number of MOV/ADD blocks
|
||||
dzBlockLen = 4 // number of clears per block
|
||||
dzBlockSize = 19 // size of instructions in a single block
|
||||
dzMovSize = 4 // size of single MOV instruction w/ offset
|
||||
dzAddSize = 4 // size of single ADD instruction
|
||||
dzClearStep = 16 // number of bytes cleared by each MOV instruction
|
||||
|
||||
dzTailLen = 4 // number of final STOSQ instructions
|
||||
dzTailSize = 2 // size of single STOSQ instruction
|
||||
|
||||
dzClearLen = dzClearStep * dzBlockLen // bytes cleared by one block
|
||||
dzSize = dzBlocks * dzBlockSize
|
||||
)
|
||||
|
||||
func duffStart(size int64) int64 {
|
||||
x, _ := duff(size)
|
||||
return x
|
||||
}
|
||||
func duffAdj(size int64) int64 {
|
||||
_, x := duff(size)
|
||||
return x
|
||||
}
|
||||
|
||||
// duff returns the offset (from duffzero, in bytes) and pointer adjust (in bytes)
|
||||
// required to use the duffzero mechanism for a block of the given size.
|
||||
func duff(size int64) (int64, int64) {
|
||||
if size < 32 || size > 1024 || size%dzClearStep != 0 {
|
||||
panic("bad duffzero size")
|
||||
}
|
||||
// TODO: arch-dependent
|
||||
steps := size / dzClearStep
|
||||
blocks := steps / dzBlockLen
|
||||
steps %= dzBlockLen
|
||||
off := dzBlockSize * (dzBlocks - blocks)
|
||||
var adj int64
|
||||
if steps != 0 {
|
||||
off -= dzAddSize
|
||||
off -= dzMovSize * steps
|
||||
adj -= dzClearStep * (dzBlockLen - steps)
|
||||
}
|
||||
return off, adj
|
||||
}
|
||||
|
||||
// mergePoint finds a block among a's blocks which dominates b and is itself
|
||||
// dominated by all of a's blocks. Returns nil if it can't find one.
|
||||
// Might return nil even if one does exist.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue