]> Cypherpunks repositories - gostls13.git/commitdiff
compress/bzip2: support superfluous Huffman levels.
authorAdam Langley <agl@golang.org>
Fri, 14 Feb 2014 22:17:19 +0000 (17:17 -0500)
committerAdam Langley <agl@golang.org>
Fri, 14 Feb 2014 22:17:19 +0000 (17:17 -0500)
These should never be found in a bzip2 file but it does appear that
there's a buggy encoder that is producing them. Since the official
bzip2 handles this case, this change makes the Go code do likewise.

With this change, the code produces the same output as the official
bzip2 code on the invalid example given in the bug.

Fixes #7279.

LGTM=r
R=golang-codereviews, r
CC=golang-codereviews
https://golang.org/cl/64010043

src/pkg/compress/bzip2/huffman.go

index 8f6b0c9cad33789f6c2622020404fcb00cacafba..75a6223d8134c42fb41ba9c95050a2bc2c45271e 100644 (file)
@@ -190,7 +190,37 @@ func buildHuffmanNode(t *huffmanTree, codes []huffmanCode, level uint32) (nodeIn
        right := codes[firstRightIndex:]
 
        if len(left) == 0 || len(right) == 0 {
-               return 0, StructuralError("superfluous level in Huffman tree")
+               // There is a superfluous level in the Huffman tree indicating
+               // a bug in the encoder. However, this bug has been observed in
+               // the wild so we handle it.
+
+               // If this function was called recursively then we know that
+               // len(codes) >= 2 because, otherwise, we would have hit the
+               // "leaf node" case, below, and not recursed.
+               //
+               // However, for the initial call it's possible that len(codes)
+               // is zero or one. Both cases are invalid because a zero length
+               // tree cannot encode anything and a length-1 tree can only
+               // encode EOF and so is superfluous. We reject both.
+               if len(codes) < 2 {
+                       return 0, StructuralError("empty Huffman tree")
+               }
+
+               // In this case the recursion doesn't always reduce the length
+               // of codes so we need to ensure termination via another
+               // mechanism.
+               if level == 31 {
+                       // Since len(codes) >= 2 the only way that the values
+                       // can match at all 32 bits is if they are equal, which
+                       // is invalid. This ensures that we never enter
+                       // infinite recursion.
+                       return 0, StructuralError("equal symbols in Huffman tree")
+               }
+
+               if len(left) == 0 {
+                       return buildHuffmanNode(t, right, level+1)
+               }
+               return buildHuffmanNode(t, left, level+1)
        }
 
        nodeIndex = uint16(t.nextNode)