From bc98e35b536785a2931f805458a0ff763c4b4b5e Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 23 Dec 2019 18:16:22 -0800 Subject: [PATCH] cmd/compile: avoid memmove -> SSA move rewrite when size is negative We should panic in this situation. Rewriting to a SSA op just leads to a compiler panic. Fixes #36259 Change-Id: I6e0bccbed7dd0fdac7ebae76b98a211947947386 Reviewed-on: https://go-review.googlesource.com/c/go/+/212405 Run-TryBot: Keith Randall TryBot-Result: Gobot Gobot Reviewed-by: Josh Bleecher Snyder --- .../compile/internal/ssa/gen/generic.rules | 1 + .../compile/internal/ssa/rewritegeneric.go | 8 +++--- test/fixedbugs/issue36259.go | 28 +++++++++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 test/fixedbugs/issue36259.go diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index 529669ec6a419..1382cdc25900b 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -1938,6 +1938,7 @@ // Inline small or disjoint runtime.memmove calls with constant length. (StaticCall {sym} s1:(Store _ (Const(64|32) [sz]) s2:(Store _ src s3:(Store {t} _ dst mem)))) + && sz >= 0 && isSameSym(sym,"runtime.memmove") && t.(*types.Type).IsPtr() // avoids TUINTPTR, see issue 30061 && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index 9d88652d4a56c..a4a2506d8efc0 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -19680,7 +19680,7 @@ func rewriteValuegeneric_OpStaticCall(v *Value) bool { b := v.Block config := b.Func.Config // match: (StaticCall {sym} s1:(Store _ (Const64 [sz]) s2:(Store _ src s3:(Store {t} _ dst mem)))) - // cond: isSameSym(sym,"runtime.memmove") && t.(*types.Type).IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst,src,sz,config) && clobber(s1) && clobber(s2) && clobber(s3) + // cond: sz >= 0 && isSameSym(sym,"runtime.memmove") && t.(*types.Type).IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst,src,sz,config) && clobber(s1) && clobber(s2) && clobber(s3) // result: (Move {t.(*types.Type).Elem()} [sz] dst src mem) for { sym := v.Aux @@ -19707,7 +19707,7 @@ func rewriteValuegeneric_OpStaticCall(v *Value) bool { t := s3.Aux mem := s3.Args[2] dst := s3.Args[1] - if !(isSameSym(sym, "runtime.memmove") && t.(*types.Type).IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, sz, config) && clobber(s1) && clobber(s2) && clobber(s3)) { + if !(sz >= 0 && isSameSym(sym, "runtime.memmove") && t.(*types.Type).IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, sz, config) && clobber(s1) && clobber(s2) && clobber(s3)) { break } v.reset(OpMove) @@ -19719,7 +19719,7 @@ func rewriteValuegeneric_OpStaticCall(v *Value) bool { return true } // match: (StaticCall {sym} s1:(Store _ (Const32 [sz]) s2:(Store _ src s3:(Store {t} _ dst mem)))) - // cond: isSameSym(sym,"runtime.memmove") && t.(*types.Type).IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst,src,sz,config) && clobber(s1) && clobber(s2) && clobber(s3) + // cond: sz >= 0 && isSameSym(sym,"runtime.memmove") && t.(*types.Type).IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst,src,sz,config) && clobber(s1) && clobber(s2) && clobber(s3) // result: (Move {t.(*types.Type).Elem()} [sz] dst src mem) for { sym := v.Aux @@ -19746,7 +19746,7 @@ func rewriteValuegeneric_OpStaticCall(v *Value) bool { t := s3.Aux mem := s3.Args[2] dst := s3.Args[1] - if !(isSameSym(sym, "runtime.memmove") && t.(*types.Type).IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, sz, config) && clobber(s1) && clobber(s2) && clobber(s3)) { + if !(sz >= 0 && isSameSym(sym, "runtime.memmove") && t.(*types.Type).IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, sz, config) && clobber(s1) && clobber(s2) && clobber(s3)) { break } v.reset(OpMove) diff --git a/test/fixedbugs/issue36259.go b/test/fixedbugs/issue36259.go new file mode 100644 index 0000000000000..246eb3527ef22 --- /dev/null +++ b/test/fixedbugs/issue36259.go @@ -0,0 +1,28 @@ +// compile + +// Copyright 2019 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 + +func rotate(s []int, m int) { + l := len(s) + m = m % l + buf := make([]int, m) + + copy(buf, s) + copy(s, s[m:]) + copy(s[l-m:], buf) +} + +func main() { + a0 := [...]int{1,2,3,4,5} + println(a0[0]) + + rotate(a0[:], 1) + println(a0[0]) + + rotate(a0[:], -3) + println(a0[0]) +}