mirror of
https://github.com/golang/go
synced 2024-11-17 23:44:48 -07:00
compress/lzw: don't follow code == hi if last is invalid.
Fixes #20597. Change-Id: Iaa059277c02e80a2fbef59cf8bb3c58d2b90fda0 Reviewed-on: https://go-review.googlesource.com/45111 Reviewed-by: David Symonds <dsymonds@golang.org>
This commit is contained in:
parent
2ddc3e940e
commit
32d42fb6ec
@ -169,7 +169,7 @@ loop:
|
|||||||
break loop
|
break loop
|
||||||
case code <= d.hi:
|
case code <= d.hi:
|
||||||
c, i := code, len(d.output)-1
|
c, i := code, len(d.output)-1
|
||||||
if code == d.hi {
|
if code == d.hi && d.last != decoderInvalidCode {
|
||||||
// code == hi is a special case which expands to the last expansion
|
// code == hi is a special case which expands to the last expansion
|
||||||
// followed by the head of the last expansion. To find the head, we walk
|
// followed by the head of the last expansion. To find the head, we walk
|
||||||
// the prefix chain until we find a literal code.
|
// the prefix chain until we find a literal code.
|
||||||
|
@ -146,6 +146,77 @@ func TestHiCodeDoesNotOverflow(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestNoLongerSavingPriorExpansions tests the decoder state when codes other
|
||||||
|
// than clear codes continue to be seen after decoder.hi and decoder.width
|
||||||
|
// reach their maximum values (4095 and 12), i.e. after we no longer save prior
|
||||||
|
// expansions. In particular, it tests seeing the highest possible code, 4095.
|
||||||
|
func TestNoLongerSavingPriorExpansions(t *testing.T) {
|
||||||
|
// Iterations is used to calculate how many input bits are needed to get
|
||||||
|
// the decoder.hi and decoder.width values up to their maximum.
|
||||||
|
iterations := []struct {
|
||||||
|
width, n int
|
||||||
|
}{
|
||||||
|
// The final term is 257, not 256, as NewReader initializes d.hi to
|
||||||
|
// d.clear+1 and the clear code is 256.
|
||||||
|
{9, 512 - 257},
|
||||||
|
{10, 1024 - 512},
|
||||||
|
{11, 2048 - 1024},
|
||||||
|
{12, 4096 - 2048},
|
||||||
|
}
|
||||||
|
nCodes, nBits := 0, 0
|
||||||
|
for _, e := range iterations {
|
||||||
|
nCodes += e.n
|
||||||
|
nBits += e.n * e.width
|
||||||
|
}
|
||||||
|
if nCodes != 3839 {
|
||||||
|
t.Fatalf("nCodes: got %v, want %v", nCodes, 3839)
|
||||||
|
}
|
||||||
|
if nBits != 43255 {
|
||||||
|
t.Fatalf("nBits: got %v, want %v", nBits, 43255)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct our input of 43255 zero bits (which gets d.hi and d.width up
|
||||||
|
// to 4095 and 12), followed by 0xfff (4095) as 12 bits, followed by 0x101
|
||||||
|
// (EOF) as 12 bits.
|
||||||
|
//
|
||||||
|
// 43255 = 5406*8 + 7, and codes are read in LSB order. The final bytes are
|
||||||
|
// therefore:
|
||||||
|
//
|
||||||
|
// xwwwwwww xxxxxxxx yyyyyxxx zyyyyyyy
|
||||||
|
// 10000000 11111111 00001111 00001000
|
||||||
|
//
|
||||||
|
// or split out:
|
||||||
|
//
|
||||||
|
// .0000000 ........ ........ ........ w = 0x000
|
||||||
|
// 1....... 11111111 .....111 ........ x = 0xfff
|
||||||
|
// ........ ........ 00001... .0001000 y = 0x101
|
||||||
|
//
|
||||||
|
// The 12 'w' bits (not all are shown) form the 3839'th code, with value
|
||||||
|
// 0x000. Just after decoder.read returns that code, d.hi == 4095 and
|
||||||
|
// d.last == 0.
|
||||||
|
//
|
||||||
|
// The 12 'x' bits form the 3840'th code, with value 0xfff or 4095. Just
|
||||||
|
// after decoder.read returns that code, d.hi == 4095 and d.last ==
|
||||||
|
// decoderInvalidCode.
|
||||||
|
//
|
||||||
|
// The 12 'y' bits form the 3841'st code, with value 0x101, the EOF code.
|
||||||
|
//
|
||||||
|
// The 'z' bit is unused.
|
||||||
|
in := make([]byte, 5406)
|
||||||
|
in = append(in, 0x80, 0xff, 0x0f, 0x08)
|
||||||
|
|
||||||
|
r := NewReader(bytes.NewReader(in), LSB, 8)
|
||||||
|
nDecoded, err := io.Copy(ioutil.Discard, r)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Copy: %v", err)
|
||||||
|
}
|
||||||
|
// nDecoded should be 3841: 3839 literal codes and then 2 decoded bytes
|
||||||
|
// from 1 non-literal code. The EOF code contributes 0 decoded bytes.
|
||||||
|
if nDecoded != int64(nCodes+2) {
|
||||||
|
t.Fatalf("nDecoded: got %v, want %v", nDecoded, nCodes+2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkDecoder(b *testing.B) {
|
func BenchmarkDecoder(b *testing.B) {
|
||||||
buf, err := ioutil.ReadFile("../testdata/e.txt")
|
buf, err := ioutil.ReadFile("../testdata/e.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user