diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go index 61a749ba0d..b48a9ea87e 100644 --- a/src/cmd/compile/internal/gc/plive.go +++ b/src/cmd/compile/internal/gc/plive.go @@ -306,6 +306,8 @@ func (lv *Liveness) valueEffects(v *ssa.Value) (int32, liveEffect) { // // Addr is a read also, as any subseqent holder of the pointer must be able // to see all the values (including initialization) written so far. + // This also prevents a variable from "coming back from the dead" and presenting + // stale pointers to the garbage collector. See issue 28445. if e&(ssa.SymRead|ssa.SymAddr) != 0 { effect |= uevar } diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 6ea46e7327..1fd335b3e7 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -264,6 +264,20 @@ func canMergeLoad(target, load *Value) bool { // to be very rare. return false } + if v.Op.SymEffect()&SymAddr != 0 { + // This case prevents an operation that calculates the + // address of a local variable from being forced to schedule + // before its corresponding VarDef. + // See issue 28445. + // v1 = LOAD ... + // v2 = VARDEF + // v3 = LEAQ + // v4 = CMPQ v1 v3 + // We don't want to combine the CMPQ with the load, because + // that would force the CMPQ to schedule before the VARDEF, which + // in turn requires the LEAQ to schedule before the VARDEF. + return false + } if v.Type.IsMemory() { if memPreds == nil { // Initialise a map containing memory states diff --git a/test/fixedbugs/issue28445.go b/test/fixedbugs/issue28445.go new file mode 100644 index 0000000000..572614051e --- /dev/null +++ b/test/fixedbugs/issue28445.go @@ -0,0 +1,16 @@ +// compile + +// 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 p + +var fp = (**float64)(nil) + +func f() { + switch fp { + case new(*float64): + println() + } +}