From: Nigel Tao Date: Sat, 29 Oct 2016 02:23:50 +0000 (+1100) Subject: compress/flate: tighten the BestSpeed max match offset bound. X-Git-Tag: go1.8beta1~449 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=590fce48849cc7f81b890d6e9b6120fc6681e19a;p=gostls13.git compress/flate: tighten the BestSpeed max match offset bound. Previously, we were off by one. Also fix a comment typo. Change-Id: Ib94d23acc56d5fccd44144f71655481f98803ac8 Reviewed-on: https://go-review.googlesource.com/32149 Reviewed-by: Joe Tsai Run-TryBot: Joe Tsai TryBot-Result: Gobot Gobot --- diff --git a/src/compress/flate/deflate_test.go b/src/compress/flate/deflate_test.go index 415e97262f..0f41695bf3 100644 --- a/src/compress/flate/deflate_test.go +++ b/src/compress/flate/deflate_test.go @@ -798,3 +798,62 @@ func TestBestSpeedMatch(t *testing.T) { } } } + +func TestBestSpeedMaxMatchOffset(t *testing.T) { + const abc, xyz = "abcdefgh", "stuvwxyz" + for _, matchBefore := range []bool{false, true} { + for _, extra := range []int{0, inputMargin - 1, inputMargin, inputMargin + 1, 2 * inputMargin} { + for offsetAdj := -5; offsetAdj <= +5; offsetAdj++ { + report := func(desc string, err error) { + t.Errorf("matchBefore=%t, extra=%d, offsetAdj=%d: %s%v", + matchBefore, extra, offsetAdj, desc, err) + } + + offset := maxMatchOffset + offsetAdj + + // Make src to be a []byte of the form + // "%s%s%s%s%s" % (abc, zeros0, xyzMaybe, abc, zeros1) + // where: + // zeros0 is approximately maxMatchOffset zeros. + // xyzMaybe is either xyz or the empty string. + // zeros1 is between 0 and 30 zeros. + // The difference between the two abc's will be offset, which + // is maxMatchOffset plus or minus a small adjustment. + src := make([]byte, offset+len(abc)+extra) + copy(src, abc) + if !matchBefore { + copy(src[offset-len(xyz):], xyz) + } + copy(src[offset:], abc) + + buf := new(bytes.Buffer) + w, err := NewWriter(buf, BestSpeed) + if err != nil { + report("NewWriter: ", err) + continue + } + if _, err := w.Write(src); err != nil { + report("Write: ", err) + continue + } + if err := w.Close(); err != nil { + report("Writer.Close: ", err) + continue + } + + r := NewReader(buf) + dst, err := ioutil.ReadAll(r) + r.Close() + if err != nil { + report("ReadAll: ", err) + continue + } + + if !bytes.Equal(dst, src) { + report("", fmt.Errorf("bytes differ after round-tripping")) + continue + } + } + } + } +} diff --git a/src/compress/flate/deflatefast.go b/src/compress/flate/deflatefast.go index 5201b2ee1c..a1636a37d6 100644 --- a/src/compress/flate/deflatefast.go +++ b/src/compress/flate/deflatefast.go @@ -55,7 +55,7 @@ func newDeflateFast() *deflateFast { return &deflateFast{cur: maxStoreBlockSize, prev: make([]byte, 0, maxStoreBlockSize)} } -// encode encodes a block given in src and encodes tokens +// encode encodes a block given in src and appends tokens // to dst and returns the result. func (e *deflateFast) encode(dst []token, src []byte) []token { // Ensure that e.cur doesn't wrap. @@ -116,8 +116,7 @@ func (e *deflateFast) encode(dst []token, src []byte) []token { nextHash = hash(now) offset := s - (candidate.offset - e.cur) - // TODO: >= should be >, and add a test for that. - if offset >= maxMatchOffset || cv != candidate.val { + if offset > maxMatchOffset || cv != candidate.val { // Out of range or not matched. cv = now continue @@ -171,8 +170,7 @@ func (e *deflateFast) encode(dst []token, src []byte) []token { e.table[currHash&tableMask] = tableEntry{offset: e.cur + s, val: uint32(x)} offset := s - (candidate.offset - e.cur) - // TODO: >= should be >, and add a test for that. - if offset >= maxMatchOffset || uint32(x) != candidate.val { + if offset > maxMatchOffset || uint32(x) != candidate.val { cv = uint32(x >> 8) nextHash = hash(cv) s++