From f14067f3c10e15343f29aed439ff60af856eb323 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 29 Oct 2018 17:02:42 -0700 Subject: [PATCH] cmd/compile: when comparing 0-size types, make sure expr side-effects survive Fixes #23837 Change-Id: I53f524d87946a0065f28a4ddbe47b40f2b43c459 Reviewed-on: https://go-review.googlesource.com/c/145757 Run-TryBot: Keith Randall Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/walk.go | 8 ++++ test/fixedbugs/issue23837.go | 70 +++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 test/fixedbugs/issue23837.go diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index c0fb5bfd28..0e07efa0d9 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -3297,6 +3297,14 @@ func walkcompare(n *Node, init *Nodes) *Node { } if expr == nil { expr = nodbool(n.Op == OEQ) + // We still need to use cmpl and cmpr, in case they contain + // an expression which might panic. See issue 23837. + t := temp(cmpl.Type) + a1 := nod(OAS, t, cmpl) + a1 = typecheck(a1, Etop) + a2 := nod(OAS, t, cmpr) + a2 = typecheck(a2, Etop) + init.Append(a1, a2) } n = finishcompare(n, expr, init) return n diff --git a/test/fixedbugs/issue23837.go b/test/fixedbugs/issue23837.go new file mode 100644 index 0000000000..7ad50837f4 --- /dev/null +++ b/test/fixedbugs/issue23837.go @@ -0,0 +1,70 @@ +// 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 + +//go:noinline +func f(p, q *struct{}) bool { + return *p == *q +} + +type T struct { + x struct{} + y int +} + +//go:noinline +func g(p, q *T) bool { + return p.x == q.x +} + +//go:noinline +func h(p, q func() struct{}) bool { + return p() == q() +} + +func fi(p, q *struct{}) bool { + return *p == *q +} + +func gi(p, q *T) bool { + return p.x == q.x +} + +func hi(p, q func() struct{}) bool { + return p() == q() +} + +func main() { + shouldPanic(func() { f(nil, nil) }) + shouldPanic(func() { g(nil, nil) }) + shouldPanic(func() { h(nil, nil) }) + shouldPanic(func() { fi(nil, nil) }) + shouldPanic(func() { gi(nil, nil) }) + shouldPanic(func() { hi(nil, nil) }) + n := 0 + inc := func() struct{} { + n++ + return struct{}{} + } + h(inc, inc) + if n != 2 { + panic("inc not called") + } + hi(inc, inc) + if n != 4 { + panic("inc not called") + } +} + +func shouldPanic(x func()) { + defer func() { + if recover() == nil { + panic("did not panic") + } + }() + x() +}