aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2020-07-16 16:56:53 -0400
committerRuss Cox <rsc@golang.org>2020-07-16 23:38:32 +0000
commit4469f5446ad754d87afb340f59c213aec2dc4fb8 (patch)
treecf93d76caacc91b604fc9b3fcdc8a0a65ea7b3ed
parent8d4330742c1866faa8b1ef575877e5afb8a4355c (diff)
downloadgo-4469f5446ad754d87afb340f59c213aec2dc4fb8.tar.gz
go-4469f5446ad754d87afb340f59c213aec2dc4fb8.zip
compress/flate: fix another deflate Reset inconsistency
While investigating #34121, fixed by CL 193605, I discovered another case where Reset was not quite resetting enough. This specific case is not a problem in Reset itself but rather that the Huffman bit writer in one code path is using uninitialized memory left over from a previous block, making the compression not choose the optimal compression method. Fixes #34121. Change-Id: I29245b28214d924e382f91e2c56b4b8a9b7da13d Reviewed-on: https://go-review.googlesource.com/c/go/+/243140 Run-TryBot: Russ Cox <rsc@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
-rw-r--r--src/compress/flate/deflate_test.go56
-rw-r--r--src/compress/flate/huffman_bit_writer.go1
2 files changed, 41 insertions, 16 deletions
diff --git a/src/compress/flate/deflate_test.go b/src/compress/flate/deflate_test.go
index 4b1ed549a4..49a0345fd1 100644
--- a/src/compress/flate/deflate_test.go
+++ b/src/compress/flate/deflate_test.go
@@ -512,33 +512,57 @@ func TestWriterReset(t *testing.T) {
t.Errorf("level %d Writer not reset after Reset", level)
}
}
- testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriter(w, NoCompression) })
- testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriter(w, DefaultCompression) })
- testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriter(w, BestCompression) })
- dict := []byte("we are the world")
- testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriterDict(w, NoCompression, dict) })
- testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriterDict(w, DefaultCompression, dict) })
- testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriterDict(w, BestCompression, dict) })
+
+ levels := []int{0, 1, 2, 5, 9}
+ for _, level := range levels {
+ t.Run(fmt.Sprint(level), func(t *testing.T) {
+ testResetOutput(t, level, nil)
+ })
+ }
+
+ t.Run("dict", func(t *testing.T) {
+ for _, level := range levels {
+ t.Run(fmt.Sprint(level), func(t *testing.T) {
+ testResetOutput(t, level, nil)
+ })
+ }
+ })
}
-func testResetOutput(t *testing.T, newWriter func(w io.Writer) (*Writer, error)) {
+func testResetOutput(t *testing.T, level int, dict []byte) {
+ writeData := func(w *Writer) {
+ msg := []byte("now is the time for all good gophers")
+ w.Write(msg)
+ w.Flush()
+
+ hello := []byte("hello world")
+ for i := 0; i < 1024; i++ {
+ w.Write(hello)
+ }
+
+ fill := bytes.Repeat([]byte("x"), 65000)
+ w.Write(fill)
+ }
+
buf := new(bytes.Buffer)
- w, err := newWriter(buf)
+ var w *Writer
+ var err error
+ if dict == nil {
+ w, err = NewWriter(buf, level)
+ } else {
+ w, err = NewWriterDict(buf, level, dict)
+ }
if err != nil {
t.Fatalf("NewWriter: %v", err)
}
- b := []byte("hello world")
- for i := 0; i < 1024; i++ {
- w.Write(b)
- }
+
+ writeData(w)
w.Close()
out1 := buf.Bytes()
buf2 := new(bytes.Buffer)
w.Reset(buf2)
- for i := 0; i < 1024; i++ {
- w.Write(b)
- }
+ writeData(w)
w.Close()
out2 := buf2.Bytes()
diff --git a/src/compress/flate/huffman_bit_writer.go b/src/compress/flate/huffman_bit_writer.go
index 3e19061f8b..f111f9f592 100644
--- a/src/compress/flate/huffman_bit_writer.go
+++ b/src/compress/flate/huffman_bit_writer.go
@@ -634,6 +634,7 @@ func (w *huffmanBitWriter) writeBlockHuff(eof bool, input []byte) {
w.literalFreq[endBlockMarker] = 1
const numLiterals = endBlockMarker + 1
+ w.offsetFreq[0] = 1
const numOffsets = 1
w.literalEncoding.generate(w.literalFreq, 15)