From: David Chase Date: Sat, 7 May 2016 00:05:02 +0000 (-0700) Subject: cmd/compile: correct sparseSet probes in regalloc to avoid index error X-Git-Tag: go1.7beta1~274 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=3c090019172afd4517360606efc50750d3e278fa;p=gostls13.git cmd/compile: correct sparseSet probes in regalloc to avoid index error In regalloc, a sparse map is preallocated for later use by spill-in-loop sinking. However, variables (spills) are added during register allocation before spill sinking, and a map query involving any of these new variables will index out of bounds in the map. To fix: 1) fix the queries to use s.orig[v.ID].ID instead, to ensure proper indexing. Note that s.orig will be nil for values that are not eligible for spilling (like memory and flags). 2) add a test. Fixes #15585. Change-Id: I8f2caa93b132a0f2a9161d2178320d5550583075 Reviewed-on: https://go-review.googlesource.com/22911 Reviewed-by: Keith Randall Run-TryBot: David Chase TryBot-Result: Gobot Gobot --- diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index 1b12c6f300..6c391aba29 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -1311,20 +1311,25 @@ func (s *regAllocState) regalloc(f *Func) { // Start with live at end. for _, li := range s.live[ss.ID] { if s.isLoopSpillCandidate(loop, s.orig[li.ID]) { + // s.live contains original IDs, use s.orig above to map back to *Value entryCandidates.setBit(li.ID, uint(whichExit)) } } // Control can also be live. - if ss.Control != nil && s.isLoopSpillCandidate(loop, ss.Control) { - entryCandidates.setBit(ss.Control.ID, uint(whichExit)) + if ss.Control != nil && s.orig[ss.Control.ID] != nil && s.isLoopSpillCandidate(loop, s.orig[ss.Control.ID]) { + entryCandidates.setBit(s.orig[ss.Control.ID].ID, uint(whichExit)) } // Walk backwards, filling in locally live values, removing those defined. for i := len(ss.Values) - 1; i >= 0; i-- { v := ss.Values[i] - entryCandidates.remove(v.ID) // Cannot be an issue, only keeps the sets smaller. + vorig := s.orig[v.ID] + if vorig != nil { + entryCandidates.remove(vorig.ID) // Cannot be an issue, only keeps the sets smaller. + } for _, a := range v.Args { - if s.isLoopSpillCandidate(loop, a) { - entryCandidates.setBit(a.ID, uint(whichExit)) + aorig := s.orig[a.ID] + if aorig != nil && s.isLoopSpillCandidate(loop, aorig) { + entryCandidates.setBit(aorig.ID, uint(whichExit)) } } } diff --git a/test/fixedbugs/issue15585.go b/test/fixedbugs/issue15585.go new file mode 100644 index 0000000000..79eb13f90d --- /dev/null +++ b/test/fixedbugs/issue15585.go @@ -0,0 +1,45 @@ +// compile + +// Copyright 2016 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 bug + +func example(n int) (rc int) { + var cc, ll, pp, rr [27]int + for q0 := 0; q0 < n-2; q0++ { + for q1 := q0 + 2; q1 < n; q1++ { + var c, d, l, p, r int + b0 := 1 << uint(q0) + b1 := 1 << uint(q1) + l = ((b0 << 1) | b1) << 1 + c = b0 | b1 | (-1 << uint(n)) + r = ((b0 >> 1) | b1) >> 1 + E: + if c != -1 { + p = ^(l | c | r) + } else { + rc++ + goto R + } + L: + if p != 0 { + lsb := p & -p + p &^= lsb + ll[d], cc[d], rr[d], pp[d] = l, c, r, p + l, c, r = (l|lsb)<<1, c|lsb, (r|lsb)>>1 + d++ + goto E + } + R: + d-- + if d >= 0 { + l, c, r, p = ll[d], cc[d], rr[d], pp[d] + goto L + } + } + } + rc <<= 1 + return +}