Skip to content

Commit

Permalink
cmd/compile: keep autos if their address reaches a control value
Browse files Browse the repository at this point in the history
Autos must be kept if their address reaches the control value of a
block. We didn't see this before because it is rare for an auto's
address to reach a control value without also reaching a phi or
being written to memory. We can probably optimize away the
comparisons that lead to this scenario since autos cannot alias
with pointers from elsewhere, however for now we take the
conservative approach and just ensure the auto is properly
initialised if its address reaches a control value.

Fixes #26407.

Change-Id: I02265793f010a9e001c3e1a5397c290c6769d4de
Reviewed-on: https://go-review.googlesource.com/124335
Reviewed-by: David Chase <drchase@google.com>
  • Loading branch information
mundaym committed Jul 17, 2018
1 parent 5890e25 commit 1546ab5
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/cmd/compile/internal/ssa/deadstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,14 @@ func elimDeadAutosGeneric(f *Func) {
for _, v := range b.Values {
changed = visit(v) || changed
}
// keep the auto if its address reaches a control value
if b.Control == nil {
continue
}
if n, ok := addr[b.Control]; ok && !used[n] {
used[n] = true
changed = true
}
}
if !changed {
break
Expand Down
58 changes: 58 additions & 0 deletions test/fixedbugs/issue26407.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// 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.

// Issue 26407: ensure that stack variables which have
// had their address taken and then used in a comparison,
// but are otherwise unused, are cleared.

package main

func main() {
poison()
test()
}

//go:noinline
func poison() {
// initialise the stack with invalid pointers
var large [256]uintptr
for i := range large {
large[i] = 1
}
use(large[:])
}

//go:noinline
func test() {
a := 2
x := &a
if x != compare(&x) {
panic("not possible")
}
}

//go:noinline
func compare(x **int) *int {
var y *int
if x == &y {
panic("not possible")
}
// grow the stack to trigger a check for invalid pointers
grow()
if x == &y {
panic("not possible")
}
return *x
}

//go:noinline
func grow() {
var large [1 << 16]uintptr
use(large[:])
}

//go:noinline
func use(_ []uintptr) { }

0 comments on commit 1546ab5

Please sign in to comment.