Skip to content

Commit 92f8fad

Browse files
committed
Avoid returning a zero byte count and a nil error on a Read at the end of a frame.
1 parent 32e39e4 commit 92f8fad

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

internal/pkg/rdr/rdr.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ func (r *Reader) Read(dst []byte) (int, error) {
4141
return 0, r.state
4242
}
4343

44+
LOOP:
4445
var (
4546
err error
4647
nRead int
@@ -61,6 +62,12 @@ func (r *Reader) Read(dst []byte) (int, error) {
6162
err = r.handleEndMark()
6263
// Set state to returned error, if there is one.
6364
r.state = err
65+
66+
// Avoid returning (0,nil) on end of frame. See https://pkg.go.dev/io#Reader
67+
if err == nil && nRead == 0 && len(dst) > 0 {
68+
goto LOOP
69+
}
70+
6471
case nRead > 0 && r.inBodyMode():
6572
// In the case that we received *SOME* data during a body read,
6673
// return the nRead count and set the return value to 'nil'.

internal/test/rd_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1323,6 +1323,48 @@ func TestReadOffsetBadSeek(t *testing.T) {
13231323
}
13241324
}
13251325

1326+
// Force a read on exactly the last block.
1327+
// Reader should not return a 0, nil read.
1328+
// (Previous versions of the reader could return a (0, nil)
1329+
// on the last block, which is undesirable behavior.
1330+
// See https://pkg.go.dev/io#Reader)
1331+
func TestReadEmptyEnd(t *testing.T) {
1332+
defer testBorrowed(t)
1333+
1334+
sample, _ := LoadSample(t, Lz4_4MB)
1335+
1336+
// First read completely to see how much data we have
1337+
rd := plz4.NewReader(bytes.NewReader(sample))
1338+
defer rd.Close()
1339+
data, err := io.ReadAll(rd)
1340+
if err != nil {
1341+
t.Fatalf("Unexpected read error %v", err)
1342+
}
1343+
sz := len(data)
1344+
1345+
nrd := plz4.NewReader(bytes.NewReader(sample))
1346+
// Read exactly the size
1347+
if n, err := io.ReadFull(nrd, data); err != nil {
1348+
t.Fatalf("Unexpected read error %v", err)
1349+
} else if n != sz {
1350+
t.Errorf("Expected read size %d, got %d", sz, n)
1351+
}
1352+
1353+
// Now read one more block, which should return an io.EOF.
1354+
n, err := nrd.Read(data)
1355+
if err != io.EOF {
1356+
t.Fatalf("Expected EOF on read, got %v", err)
1357+
}
1358+
1359+
if n != 0 {
1360+
t.Errorf("Expected read size 0, got %d", n)
1361+
}
1362+
1363+
if err := nrd.Close(); err != nil {
1364+
t.Errorf("Expected nil error on close: %v", err)
1365+
}
1366+
}
1367+
13261368
// Validate parse and callback on dictId.
13271369
func TestReadDictId(t *testing.T) {
13281370
maybeSkip(t)

0 commit comments

Comments
 (0)