Skip to content

Commit

Permalink
cmd/compile: reverse order of slice bounds checks
Browse files Browse the repository at this point in the history
Turns out this makes the fix for 28797 unnecessary, because this order
ensures that the RHS of IsSliceInBounds ops are always nonnegative.

The real reason for this change is that it also makes dealing with
<0 values easier for reporting values in bounds check panics (issue #30116).

Makes cmd/go negligibly smaller.

Update #28797

Change-Id: I1f25ba6d2b3b3d4a72df3105828aa0a4b629ce85
Reviewed-on: https://go-review.googlesource.com/c/go/+/166377
Run-TryBot: Keith Randall <[email protected]>
Reviewed-by: Brad Fitzpatrick <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
  • Loading branch information
randall77 committed Mar 9, 2019
1 parent 3cf89e5 commit 83a33d3
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 30 deletions.
33 changes: 8 additions & 25 deletions src/cmd/compile/internal/gc/ssa.go
Original file line number Diff line number Diff line change
Expand Up @@ -4029,6 +4029,7 @@ func (s *state) nilCheck(ptr *ssa.Value) {
}

// boundsCheck generates bounds checking code. Checks if 0 <= idx < len, branches to exit if not.
// len must be known to be nonnegative.
// Starts a new block on return.
// idx is already converted to full int width.
func (s *state) boundsCheck(idx, len *ssa.Value) {
Expand All @@ -4041,34 +4042,14 @@ func (s *state) boundsCheck(idx, len *ssa.Value) {
s.check(cmp, panicindex)
}

func couldBeNegative(v *ssa.Value) bool {
switch v.Op {
case ssa.OpSliceLen, ssa.OpSliceCap, ssa.OpStringLen:
return false
case ssa.OpConst64:
return v.AuxInt < 0
case ssa.OpConst32:
return int32(v.AuxInt) < 0
}
return true
}

// sliceBoundsCheck generates slice bounds checking code. Checks if 0 <= idx <= len, branches to exit if not.
// len must be known to be nonnegative.
// Starts a new block on return.
// idx and len are already converted to full int width.
func (s *state) sliceBoundsCheck(idx, len *ssa.Value) {
if Debug['B'] != 0 {
return
}
if couldBeNegative(len) {
// OpIsSliceInBounds requires second arg not negative; if it's not obviously true, must check.
cmpop := ssa.OpGeq64
if len.Type.Size() == 4 {
cmpop = ssa.OpGeq32
}
cmp := s.newValue2(cmpop, types.Types[TBOOL], len, s.zeroVal(len.Type))
s.check(cmp, panicslice)
}

// bounds check
cmp := s.newValue2(ssa.OpIsSliceInBounds, types.Types[TBOOL], idx, len)
Expand Down Expand Up @@ -4332,13 +4313,15 @@ func (s *state) slice(t *types.Type, v, i, j, k *ssa.Value, bounded bool) (p, l,

if !bounded {
// Panic if slice indices are not in bounds.
s.sliceBoundsCheck(i, j)
if j != k {
s.sliceBoundsCheck(j, k)
}
// Make sure we check these in reverse order so that we're always
// comparing against a value known to be nonnegative. See issue 28797.
if k != cap {
s.sliceBoundsCheck(k, cap)
}
if j != k {
s.sliceBoundsCheck(j, k)
}
s.sliceBoundsCheck(i, j)
}

// Generate the following code assuming that indexes are in bounds.
Expand Down
6 changes: 3 additions & 3 deletions test/loopbce.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func f5(a [10]int) int {

func f6(a []int) {
for i := range a { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
b := a[0:i] // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$" "(\([0-9]+\) )?Proved Geq64$"
b := a[0:i] // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
f6(b)
}
}
Expand Down Expand Up @@ -186,10 +186,10 @@ func k0(a [100]int) [100]int {

func k1(a [100]int) [100]int {
for i := 10; i < 90; i++ { // ERROR "Induction variable: limits \[10,90\), increment 1$"
useSlice(a[:i-11]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
useSlice(a[:i-11])
useSlice(a[:i-10]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
useSlice(a[:i-5]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
useSlice(a[:i]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$" "(\([0-9]+\) )?Proved Geq64$"
useSlice(a[:i]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
useSlice(a[:i+5]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
useSlice(a[:i+10]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
useSlice(a[:i+11]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
Expand Down
4 changes: 2 additions & 2 deletions test/prove.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ func f11b(a []int, i int) {

func f11c(a []int, i int) {
useSlice(a[:i])
useSlice(a[:i]) // ERROR "Proved Geq64$" "Proved IsSliceInBounds$"
useSlice(a[:i]) // ERROR "Proved IsSliceInBounds$"
}

func f11d(a []int, i int) {
Expand Down Expand Up @@ -469,7 +469,7 @@ func f17(b []int) {
// using the derived relation between len and cap.
// This depends on finding the contradiction, since we
// don't query this condition directly.
useSlice(b[:i]) // ERROR "Proved Geq64$" "Proved IsSliceInBounds$"
useSlice(b[:i]) // ERROR "Proved IsSliceInBounds$"
}
}

Expand Down

0 comments on commit 83a33d3

Please sign in to comment.