Skip to content

cmd/compile: improve BCE to detect safe unbounded slicing #35483

Closed
@nhooyr

Description

@nhooyr

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.

@renthraysk stated:

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.

Activity

josharian

josharian commented on Nov 9, 2019

@josharian
Contributor
changed the title [-]cmd/go: improve BCE to detect safe unbounded slicing[/-] [+]cmd/compile: improve BCE to detect safe unbounded slicing[/+] on Nov 10, 2019
added
NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.
on Nov 10, 2019
added this to the Unplanned milestone on Nov 10, 2019
zdjones

zdjones commented on Nov 11, 2019

@zdjones
Contributor

This is a duplicate of #24876. Also see #19126

The issue is that the prove pass does not currently do any arithimetic when assesing b[16:] and therefore has no information about the length of the resulting slice. see this comment: #19126 (comment).

I have a chain of CLs that fix this, but they are not complete this cycle.

zdjones

zdjones commented on Nov 11, 2019

@zdjones
Contributor

Here is the CL chain that fixes this issue: https://go-review.googlesource.com/c/go/+/190657

agnivade

agnivade commented on Nov 11, 2019

@agnivade
Contributor

Closing as a duplicate.

locked and limited conversation to collaborators on Nov 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.Performance

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @josharian@agnivade@ALTree@zdjones@gopherbot

        Issue actions

          cmd/compile: improve BCE to detect safe unbounded slicing · Issue #35483 · golang/go