LZX: Fix unaligned block failure

This fixes the case where an unaligned block lands on a 16-bit boundary.
This commit is contained in:
John Starks
2016-04-06 13:45:37 -07:00
parent 9e60d867bd
commit bad3e111b5
+20 -13
View File
@@ -21,7 +21,7 @@ const (
maxBlockSize = 32768 maxBlockSize = 32768
windowSize = 32768 windowSize = 32768
treePathLenCount = 17 maxTreePathLen = 16
e8filesize = 12000000 e8filesize = 12000000
maxe8offset = 0x3fffffff maxe8offset = 0x3fffffff
@@ -97,8 +97,8 @@ func (f *decompressor) feed() bool {
// getBits retrieves the next n bits from the byte stream. n // getBits retrieves the next n bits from the byte stream. n
// must be <= 16. It sets f.err on error. // must be <= 16. It sets f.err on error.
func (f *decompressor) getBits(n byte) uint16 { func (f *decompressor) getBits(n byte) uint16 {
if f.nbits < 16 { if f.nbits < n {
if !f.feed() && n > f.nbits { if !f.feed() {
f.err = io.ErrUnexpectedEOF f.err = io.ErrUnexpectedEOF
} }
} }
@@ -115,12 +115,12 @@ type huffman struct {
} }
// buildTable builds a huffman decoding table from a slice of code lengths, // buildTable builds a huffman decoding table from a slice of code lengths,
// one per code, in order. Each code length must be less than treePathLenCount. // one per code, in order. Each code length must be <= maxTreePathLen.
// See https://en.wikipedia.org/wiki/Canonical_Huffman_code. // See https://en.wikipedia.org/wiki/Canonical_Huffman_code.
func buildTable(codelens []byte) *huffman { func buildTable(codelens []byte) *huffman {
// Determine the number of codes of each length, and the // Determine the number of codes of each length, and the
// maximum length. // maximum length.
var count [treePathLenCount]uint var count [maxTreePathLen + 1]uint
var max byte var max byte
for _, cl := range codelens { for _, cl := range codelens {
count[cl]++ count[cl]++
@@ -134,7 +134,7 @@ func buildTable(codelens []byte) *huffman {
} }
// Determine the first code of each length. // Determine the first code of each length.
var first [treePathLenCount]uint var first [maxTreePathLen + 1]uint
code := uint(0) code := uint(0)
for i := byte(1); i <= max; i++ { for i := byte(1); i <= max; i++ {
code <<= 1 code <<= 1
@@ -178,7 +178,7 @@ func (f *decompressor) getCode(h *huffman) uint16 {
f.err = errCorrupt f.err = errCorrupt
return 0 return 0
} }
if f.nbits < 16 { if f.nbits < maxTreePathLen {
f.feed() f.feed()
} }
// For codes with length < h.maxbits, it doesn't matter // For codes with length < h.maxbits, it doesn't matter
@@ -309,14 +309,21 @@ func (f *decompressor) readBlockHeader() (byte, uint16, error) {
case verbatimBlock, alignedOffsetBlock: case verbatimBlock, alignedOffsetBlock:
// The caller will read the huffman trees. // The caller will read the huffman trees.
case uncompressedBlock: case uncompressedBlock:
// Not sure if this can happen... if f.nbits > 16 {
if f.nbits > 16 || f.nbits == 0 { panic("impossible: more than one 16-bit word remains")
return 0, 0, errCorrupt
} }
// Drop the remaining bits in the current 16-bit word. // Drop the remaining bits in the current 16-bit word
f.nbits = 0 // If there are no bits left, discard a full 16-bit word.
f.c = 0 n := f.nbits
if n == 0 {
n = 16
}
f.getBits(n)
if f.err != nil {
return 0, 0, f.err
}
// Read the LRU values for the next block. // Read the LRU values for the next block.
var lru [12]byte var lru [12]byte