internal/coverage/slicewriter: fix off-by-1 error in seek utilities

The slicewriter Seek method was being too restrictive on offsets
accepted, due to an off-by-one problem in the error checking code.
This fixes the problem and touches up the unit tests.

Change-Id: I75d6121551de19ec9275f0e331810db231db6ea9
Reviewed-on: https://go-review.googlesource.com/c/go/+/488116
Run-TryBot: Than McIntosh <thanm@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Than McIntosh 2023-04-24 10:33:01 -04:00
parent ada0eec827
commit 7b89531860
2 changed files with 10 additions and 7 deletions

View file

@ -38,21 +38,21 @@ func (sws *WriteSeeker) Write(p []byte) (n int, err error) {
func (sws *WriteSeeker) Seek(offset int64, whence int) (int64, error) { func (sws *WriteSeeker) Seek(offset int64, whence int) (int64, error) {
switch whence { switch whence {
case io.SeekStart: case io.SeekStart:
if sws.off != offset && (offset < 0 || offset >= int64(len(sws.payload))) { if sws.off != offset && (offset < 0 || offset > int64(len(sws.payload))) {
return 0, fmt.Errorf("invalid seek: new offset %d (out of range [0 %d]", offset, len(sws.payload)) return 0, fmt.Errorf("invalid seek: new offset %d (out of range [0 %d]", offset, len(sws.payload))
} }
sws.off = offset sws.off = offset
return offset, nil return offset, nil
case io.SeekCurrent: case io.SeekCurrent:
newoff := sws.off + offset newoff := sws.off + offset
if newoff != sws.off && (newoff < 0 || newoff >= int64(len(sws.payload))) { if newoff != sws.off && (newoff < 0 || newoff > int64(len(sws.payload))) {
return 0, fmt.Errorf("invalid seek: new offset %d (out of range [0 %d]", newoff, len(sws.payload)) return 0, fmt.Errorf("invalid seek: new offset %d (out of range [0 %d]", newoff, len(sws.payload))
} }
sws.off += offset sws.off += offset
return sws.off, nil return sws.off, nil
case io.SeekEnd: case io.SeekEnd:
newoff := int64(len(sws.payload)) + offset newoff := int64(len(sws.payload)) + offset
if newoff != sws.off && (newoff < 0 || newoff >= int64(len(sws.payload))) { if newoff != sws.off && (newoff < 0 || newoff > int64(len(sws.payload))) {
return 0, fmt.Errorf("invalid seek: new offset %d (out of range [0 %d]", newoff, len(sws.payload)) return 0, fmt.Errorf("invalid seek: new offset %d (out of range [0 %d]", newoff, len(sws.payload))
} }
sws.off = newoff sws.off = newoff

View file

@ -47,12 +47,13 @@ func TestSliceWriter(t *testing.T) {
sleq(t, b, p) sleq(t, b, p)
} }
sk := func(t *testing.T, ws *WriteSeeker, offset int64, whence int) { sk := func(t *testing.T, ws *WriteSeeker, offset int64, whence int) int64 {
t.Helper() t.Helper()
_, err := ws.Seek(offset, whence) off, err := ws.Seek(offset, whence)
if err != nil { if err != nil {
t.Fatalf("unexpected seek error: %v", err) t.Fatalf("unexpected seek error: %v", err)
} }
return off
} }
wp1 := []byte{1, 2} wp1 := []byte{1, 2}
@ -80,6 +81,8 @@ func TestSliceWriter(t *testing.T) {
rf(t, ws, []byte{2, 7}) rf(t, ws, []byte{2, 7})
sk(t, ws, -4, io.SeekEnd) sk(t, ws, -4, io.SeekEnd)
rf(t, ws, []byte{2, 7}) rf(t, ws, []byte{2, 7})
off := sk(t, ws, 0, io.SeekEnd)
sk(t, ws, off, io.SeekStart)
// seek back and overwrite // seek back and overwrite
sk(t, ws, 1, io.SeekStart) sk(t, ws, 1, io.SeekStart)
@ -98,7 +101,7 @@ func TestSliceWriter(t *testing.T) {
if err == nil { if err == nil {
t.Fatalf("expected error on invalid -1 seek") t.Fatalf("expected error on invalid -1 seek")
} }
_, err = ws.Seek(int64(len(ws.BytesWritten())), io.SeekStart) _, err = ws.Seek(int64(len(ws.BytesWritten())+1), io.SeekStart)
if err == nil { if err == nil {
t.Fatalf("expected error on invalid %d seek", len(ws.BytesWritten())) t.Fatalf("expected error on invalid %d seek", len(ws.BytesWritten()))
} }
@ -108,7 +111,7 @@ func TestSliceWriter(t *testing.T) {
if err == nil { if err == nil {
t.Fatalf("expected error on invalid -1 seek") t.Fatalf("expected error on invalid -1 seek")
} }
_, err = ws.Seek(int64(len(ws.BytesWritten())), io.SeekCurrent) _, err = ws.Seek(int64(len(ws.BytesWritten())+1), io.SeekCurrent)
if err == nil { if err == nil {
t.Fatalf("expected error on invalid %d seek", len(ws.BytesWritten())) t.Fatalf("expected error on invalid %d seek", len(ws.BytesWritten()))
} }