Closed
Description
See #31586 (comment)
Core problem can be reduced to:
package scratch
import "encoding/binary"
func A1(b []byte) {
key64 := uint64(1024)
for len(b) >= 32 {
v := binary.LittleEndian.Uint64(b)
binary.LittleEndian.PutUint64(b, v^key64)
v = binary.LittleEndian.Uint64(b[8:])
binary.LittleEndian.PutUint64(b[8:], v^key64)
v = binary.LittleEndian.Uint64(b[16:])
binary.LittleEndian.PutUint64(b[16:], v^key64)
v = binary.LittleEndian.Uint64(b[24:])
binary.LittleEndian.PutUint64(b[24:], v^key64)
b = b[32:]
}
}
func A2(b []byte) {
key64 := uint64(1024)
for len(b) >= 32 {
v := binary.LittleEndian.Uint64(b)
binary.LittleEndian.PutUint64(b, v^key64)
v = binary.LittleEndian.Uint64(b[8:16])
binary.LittleEndian.PutUint64(b[8:16], v^key64)
v = binary.LittleEndian.Uint64(b[16:24])
binary.LittleEndian.PutUint64(b[16:24], v^key64)
v = binary.LittleEndian.Uint64(b[24:32])
binary.LittleEndian.PutUint64(b[24:32], v^key64)
b = b[32:]
}
}
BCE:
$ go build -gcflags="-d=ssa/check_bce/debug=1" scratch.go
# command-line-arguments
./scratch.go:10:34: Found IsInBounds
./scratch.go:12:34: Found IsInBounds
./scratch.go:14:34: Found IsInBounds
Bound checks remain in A1 even though they are not needed but are eliminated in A2 due to the explicit and not unbounded slices.
It was the _ = b[7] line in PutUint64() that was cause the bounds checks. The compiler failed to prove it's not needed with PutUint64(b[8:], x) however it does eliminate the first check in PutUint64(b, x).
I'm on 1.13.4 on macOS.