From df9f4f14b988c1a6dd0b5106ed1f3720c43fdd28 Mon Sep 17 00:00:00 2001 From: =?utf8?q?R=C3=A9my=20Oudompheng?= Date: Mon, 1 Apr 2013 21:01:50 +0200 Subject: [PATCH] cmd/gc: do not reuse bool temporaries for composite equality. Reusing it when multiple comparisons occurred in the same function call led to bad overwriting. Fixes #5162. R=golang-dev, daniel.morsing CC=golang-dev https://golang.org/cl/8174047 --- src/cmd/gc/walk.c | 18 +++++--- test/fixedbugs/issue5162.go | 88 +++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 test/fixedbugs/issue5162.go diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 50e05fc3cf..4e42b182fe 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -2856,11 +2856,19 @@ walkcompare(Node **np, NodeList **init) typecheck(&call, Etop); walkstmt(&call); *init = list(*init, call); - - if(n->op == OEQ) - r = tempbool; - else - r = nod(ONOT, tempbool, N); + + // tempbool cannot be used directly as multiple comparison + // expressions may exist in the same statement. Create another + // temporary to hold the value (its address is not taken so it can + // be optimized away). + r = temp(types[TBOOL]); + a = nod(OAS, r, tempbool); + typecheck(&a, Etop); + walkstmt(&a); + *init = list(*init, a); + + if(n->op != OEQ) + r = nod(ONOT, r, N); typecheck(&r, Erv); walkexpr(&r, init); *np = r; diff --git a/test/fixedbugs/issue5162.go b/test/fixedbugs/issue5162.go new file mode 100644 index 0000000000..b14eae7863 --- /dev/null +++ b/test/fixedbugs/issue5162.go @@ -0,0 +1,88 @@ +// runoutput + +// Copyright 2013 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 5162: bad array equality when multiple comparisons +// happen in the same expression. + +package main + +import ( + "fmt" + "strings" +) + +const template = ` +func CheckEqNNN_TTT() { + onesA := [NNN]ttt{ONES} + onesB := [NNN]ttt{ONES} + twos := [NNN]ttt{TWOS} + if onesA != onesB { + println("onesA != onesB in CheckEqNNN_TTT") + } + if onesA == twos { + println("onesA == twos in CheckEqNNN_TTT") + } + if onesB == twos { + println("onesB == twos in CheckEqNNN_TTT") + } + if s := fmt.Sprint(onesA == onesB, onesA != twos, onesB != twos); s != "true true true" { + println("fail in CheckEqNNN_TTT:", s) + } +} + +func CheckEqNNN_TTTExtraVar() { + onesA := [NNN]ttt{ONES} + onesB := [NNN]ttt{ONES} + twos := [NNN]ttt{TWOS} + onesX := onesA + if onesA != onesB { + println("onesA != onesB in CheckEqNNN_TTTExtraVar") + } + if onesA == twos { + println("onesA == twos in CheckEqNNN_TTTExtraVar") + } + if onesB == twos { + println("onesB == twos in CheckEqNNN_TTTExtraVar") + } + if s := fmt.Sprint(onesA == onesB, onesA != twos, onesB != twos); s != "true true true" { + println("fail in CheckEqNNN_TTTExtraVar:", s) + } + if s := fmt.Sprint(onesB == onesX); s != "true" { + println("extra var fail in CheckEqNNN_TTTExtraVar") + } +} +` + +func main() { + fmt.Print("// run\n\n") + fmt.Print("// THIS FILE IS AUTO-GENERATED\n\n") + fmt.Print("package main\n\n") + fmt.Println(`import "fmt"`) + + types := []string{ + "int", "int8", "int16", "int32", "int64", + "uint", "uint8", "uint16", "uint32", "uint64", + "float32", "float64"} + tocall := make([]string, 0, 32*len(types)) + for i := 1; i <= 32; i++ { + for _, typ := range types { + src := template + src = strings.Replace(src, "NNN", fmt.Sprint(i), -1) + src = strings.Replace(src, "TTT", strings.Title(typ), -1) + src = strings.Replace(src, "ttt", typ, -1) + src = strings.Replace(src, "ONES", "1"+strings.Repeat(", 1", i-1), -1) + src = strings.Replace(src, "TWOS", "2"+strings.Repeat(", 2", i-1), -1) + fmt.Print(src) + tocall = append(tocall, fmt.Sprintf("CheckEq%d_%s", i, strings.Title(typ))) + } + } + fmt.Println("func main() {") + for _, fun := range tocall { + fmt.Printf("\t%s()\n", fun) + fmt.Printf("\t%sExtraVar()\n", fun) + } + fmt.Println("}") +} -- 2.50.0