index/suffixarray: fix incorrect condition

CL 771782 introduced an extra index verification when reading in
suffixarray indices. However, instead of testing against the overall
suffixarray length, the condition checked against the (current) slice
length which may be smaller than the indexarray length.
This resulted in an error being reported when benchmarking a larger
suffixarray that recorded its data using multiple data slices.
The benchmark itself was not expecting an error and instead responded
with a panic.

Fix the condition by testing against the correct length.
Also, adjust the testSaveRestore signature so we can pass in non-nil
values so that the benchmark reports an error rather than panicking
(before the bug fix).

Fixes #79207.

Change-Id: I523944ab1b133641e045a35435af6b6e2feed05d
Reviewed-on: https://go-review.googlesource.com/c/go/+/774482
Reviewed-by: Robert Griesemer <gri@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Keith Randall <khr@google.com>
This commit is contained in:
Robert Griesemer 2026-05-05 15:41:54 -07:00 committed by Gopher Robot
parent 628674a0c1
commit 07840ceeed
2 changed files with 8 additions and 7 deletions

View file

@ -119,9 +119,9 @@ func writeSlice(w io.Writer, buf []byte, data ints) (n int, err error) {
var errCorrupted = errors.New("suffixarray: data corrupted")
// readSlice reads data[:n] from r and returns n.
// readSlice reads data[:n] from r and returns n; maxIndex is the length of the suffix array.
// It uses buf to buffer the read.
func readSlice(r io.Reader, buf []byte, data ints) (n int, err error) {
func readSlice(r io.Reader, buf []byte, data ints, maxIndex uint64) (n int, err error) {
// read buffer size
var size64 int64
size64, err = readInt(r, buf)
@ -146,8 +146,8 @@ func readSlice(r io.Reader, buf []byte, data ints) (n int, err error) {
// - prevent index-out-of-bounds panic if there are more indices than expected
// (was go.dev/issue/53352)
// - prevent index-out-of-bounds panic in a future Lookup
// by ensuring all indices x satisfy x < len
if n >= len || x >= uint64(len) {
// by ensuring all indices x satisfy x < maxIndex
if n >= len || x >= maxIndex {
return n, errCorrupted
}
data.set(n, int64(x))
@ -200,7 +200,7 @@ func (x *Index) Read(r io.Reader) error {
// read index
sa := x.sa
for sa.len() > 0 {
n, err := readSlice(r, buf, sa)
n, err := readSlice(r, buf, sa, uint64(n))
if err != nil {
return err
}

View file

@ -249,7 +249,7 @@ func equal(x, y *Index) bool {
}
// returns the serialized index size
func testSaveRestore(t *testing.T, tc *testCase, x *Index) int {
func testSaveRestore(t testing.TB, tc *testCase, x *Index) int {
var buf bytes.Buffer
if err := x.Write(&buf); err != nil {
t.Errorf("failed writing index %s (%s)", tc.name, err)
@ -590,13 +590,14 @@ func BenchmarkSaveRestore(b *testing.B) {
if ^uint(0) == 0xffffffff && bits == 64 {
continue
}
tc := &testCase{name: "BenchmarkSaveRestore"}
b.Run(fmt.Sprintf("bits=%d", bits), func(b *testing.B) {
cleanup := setBits(bits)
defer cleanup()
b.StopTimer()
x := New(data)
size := testSaveRestore(nil, nil, x) // verify correctness
size := testSaveRestore(b, tc, x) // verify correctness
buf := bytes.NewBuffer(make([]byte, size)) // avoid growing
b.SetBytes(int64(size))
b.StartTimer()