Skip to content

Commit 72cd4a9

Browse files
authored
zstd: Fix extra CRC written with multiple Close calls (#1017)
* zstd: Fix extra CRC written with multiple Close calls * Also check write/flush after close. Fixes #1016
1 parent dbd6c38 commit 72cd4a9

File tree

3 files changed

+37
-4
lines changed

3 files changed

+37
-4
lines changed

zstd/encoder.go

+23-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package zstd
66

77
import (
88
"crypto/rand"
9+
"errors"
910
"fmt"
1011
"io"
1112
"math"
@@ -149,6 +150,9 @@ func (e *Encoder) ResetContentSize(w io.Writer, size int64) {
149150
// and write CRC if requested.
150151
func (e *Encoder) Write(p []byte) (n int, err error) {
151152
s := &e.state
153+
if s.eofWritten {
154+
return 0, ErrEncoderClosed
155+
}
152156
for len(p) > 0 {
153157
if len(p)+len(s.filling) < e.o.blockSize {
154158
if e.o.crc {
@@ -288,6 +292,9 @@ func (e *Encoder) nextBlock(final bool) error {
288292
s.filling, s.current, s.previous = s.previous[:0], s.filling, s.current
289293
s.nInput += int64(len(s.current))
290294
s.wg.Add(1)
295+
if final {
296+
s.eofWritten = true
297+
}
291298
go func(src []byte) {
292299
if debugEncoder {
293300
println("Adding block,", len(src), "bytes, final:", final)
@@ -303,9 +310,6 @@ func (e *Encoder) nextBlock(final bool) error {
303310
blk := enc.Block()
304311
enc.Encode(blk, src)
305312
blk.last = final
306-
if final {
307-
s.eofWritten = true
308-
}
309313
// Wait for pending writes.
310314
s.wWg.Wait()
311315
if s.writeErr != nil {
@@ -401,12 +405,20 @@ func (e *Encoder) Flush() error {
401405
if len(s.filling) > 0 {
402406
err := e.nextBlock(false)
403407
if err != nil {
408+
// Ignore Flush after Close.
409+
if errors.Is(s.err, ErrEncoderClosed) {
410+
return nil
411+
}
404412
return err
405413
}
406414
}
407415
s.wg.Wait()
408416
s.wWg.Wait()
409417
if s.err != nil {
418+
// Ignore Flush after Close.
419+
if errors.Is(s.err, ErrEncoderClosed) {
420+
return nil
421+
}
410422
return s.err
411423
}
412424
return s.writeErr
@@ -422,6 +434,9 @@ func (e *Encoder) Close() error {
422434
}
423435
err := e.nextBlock(true)
424436
if err != nil {
437+
if errors.Is(s.err, ErrEncoderClosed) {
438+
return nil
439+
}
425440
return err
426441
}
427442
if s.frameContentSize > 0 {
@@ -459,6 +474,11 @@ func (e *Encoder) Close() error {
459474
}
460475
_, s.err = s.w.Write(frame)
461476
}
477+
if s.err == nil {
478+
s.err = ErrEncoderClosed
479+
return nil
480+
}
481+
462482
return s.err
463483
}
464484

zstd/encoder_test.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package zstd
66

77
import (
88
"bytes"
9+
"errors"
910
"fmt"
1011
"io"
1112
"math/rand"
@@ -278,13 +279,21 @@ func TestEncoderRegression(t *testing.T) {
278279
if err != nil {
279280
t.Error(err)
280281
}
282+
err = enc.Close()
283+
if err != nil {
284+
t.Error(err)
285+
}
286+
_, err = enc.Write([]byte{1, 2, 3, 4})
287+
if !errors.Is(err, ErrEncoderClosed) {
288+
t.Errorf("unexpected error: %v", err)
289+
}
281290
encoded = dst.Bytes()
282291
if len(encoded) > enc.MaxEncodedSize(len(in)) {
283292
t.Errorf("max encoded size for %v: got: %d, want max: %d", len(in), len(encoded), enc.MaxEncodedSize(len(in)))
284293
}
285294
got, err = dec.DecodeAll(encoded, make([]byte, 0, len(in)/2))
286295
if err != nil {
287-
t.Logf("error: %v\nwant: %v\ngot: %v", err, in, got)
296+
t.Logf("error: %v\nwant: %v\ngot: %v", err, len(in), len(got))
288297
t.Error(err)
289298
}
290299
})

zstd/zstd.go

+4
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ var (
8888
// Close has been called.
8989
ErrDecoderClosed = errors.New("decoder used after Close")
9090

91+
// ErrEncoderClosed will be returned if the Encoder was used after
92+
// Close has been called.
93+
ErrEncoderClosed = errors.New("encoder used after Close")
94+
9195
// ErrDecoderNilInput is returned when a nil Reader was provided
9296
// and an operation other than Reset/DecodeAll/Close was attempted.
9397
ErrDecoderNilInput = errors.New("nil input provided as reader")

0 commit comments

Comments
 (0)